b2c信息网

您现在的位置是:首页 > 今日新闻 > 正文

今日新闻

mybatis源码电子版(通用源码阅读指导书MyBatis源码详解)

hacker2022-07-04 20:57:54今日新闻84
本文目录一览:1、《深入浅出MyBatis技术原理与实战》pdf下载在线阅读全文,求百度网盘云资源

本文目录一览:

《深入浅出MyBatis技术原理与实战》pdf下载在线阅读全文,求百度网盘云资源

《深入浅出MyBatis技术原理与实战》百度网盘pdf最新全集下载:

链接:

?pwd=gijo 提取码:gijo

简介:随着大数据时代的到来,Java持久层框架MyBatis已经成为越来越多企业的选择。遗憾的是,时至今日国内依然没有一本讨论MyBatis的书,这增加了初学者的学习难度,初学者往往只能基于零星的案例来学习MyBatis,无法系统地掌握MyBatis,更不用说精通了。《深入浅出MyBatis技术原理与实战》是笔者通过大量实践和研究源码后创作而成的,是国内第一本系统介绍MyBatis的著作本书分为3个部分,依次介绍了MyBatis的基础应用、原理及插件开发、实践应用,使读者能够由法入深、循序渐进地掌握MyBatis技术。首先,本书在官方API的基础上完善了许多重要的论述和实例,并且给出了实操建议,帮助读者正确掌握MyBatis。其次,本书详细讲述了MyBatis的内部运行原理,并全面讨论了插件的开发。最后,本着学以致用的原则,笔者阐述了MyBatis-Spring项目和一些MyBatis开发常见的实例,使读者能够学得会,用得好。  

怎么没有mybatis源码解析相关的文档

我们还记得是这样配置sqlSessionFactory的:

[java] view plain copy

bean id="sqlSessionFactory" class="c1ee-0312-99eb-f14c org.mybatis.spring.SqlSessionFactoryBean"

property name="dataSource" ref="dataSource" /

property name="configLocation" value="classpath:configuration.xml"/property

property name="mapperLocations" value="classpath:com/xxx/mybatis/mapper/*.xml"/

property name="typeAliasesPackage" value="com.tiantian.mybatis.model" /

/bean

这里配置了一个mapperLocations属性,它是一个表达式,sqlSessionFactory会根据这个表达式读取包com.xxx.mybaits.mapper下面的所有xml格式文件,那么具体是怎么根据这个属性来读取配置文件的呢?

答案就在SqlSessionFactoryBean类中的buildSqlSessionFactory方法中:

[java] view plain copy

if (!isEmpty(this.mapperLocations)) {

for (Resource mapperLocation : this.mapperLocations) {

if (mapperLocation == null) {

continue;

}

try {

XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),

configuration, mapperLocation.toString(), configuration.getSqlFragments());

xmlMapperBuilder.parse();

} catch (Exception e) {

throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);

} finally {

ErrorContext.instance().reset();

}

if (logger.isDebugEnabled()) {

logger.debug("Parsed mapper file: '" + mapperLocation + "'");

}

}

}

mybatis使用XMLMapperBuilder类的实例来解析mapper配置文件。

[java] view plain copy

public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, MapString, XNode sqlFragments) {

this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()),

configuration, resource, sqlFragments);

}

[java] view plain copy

private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, MapString, XNode sqlFragments) {

super(configuration);

this.builderAssistant = new MapperBuilderAssistant(configuration, resource);

this.parser = parser;

this.sqlFragments = sqlFragments;

this.resource = resource;

}

接着系统调用xmlMapperBuilder的parse方法解析mapper。

[java] view plain copy

public void parse() {

//如果configuration对象还没加载xml配置文件(避免重复加载,实际上是确认是否解析了mapper节点的属性及内容,

//为解析它的子节点如cache、sql、select、resultMap、parameterMap等做准备),

//则从输入流中解析mapper节点,然后再将resource的状态置为已加载

if (!configuration.isResourceLoaded(resource)) {

configurationElement(parser.evalNode("/mapper"));

configuration.addLoadedResource(resource);

bindMapperForNamespace();

}

//解析在configurationElement函数中处理resultMap时其extends属性指向的父对象还没被处理的resultMap节点

parsePendingResultMaps();

//解析在configurationElement函数中处理cache-ref时其指向的对象不存在的cache节点(如果cache-ref先于其指向的cache节点加载就会出现这种情况)

parsePendingChacheRefs();

//同上,如果cache没加载的话处理statement时也会抛出异常

parsePendingStatements();

}

mybatis解析mapper的xml文件的过程已经很明显了,接下来我们看看它是怎么解析mapper的:

[java] view plain copy

private void configurationElement(XNode context) {

try {

//获取mapper节点的namespace属性

String namespace = context.getStringAttribute("namespace");

if (namespace.equals("")) {

throw new BuilderException("Mapper's namespace cannot be empty");

}

//设置当前namespace

builderAssistant.setCurrentNamespace(namespace);

//解析mapper的cache-ref节点

cacheRefElement(context.evalNode("cache-ref"));

//解析mapper的cache节点

cacheElement(context.evalNode("cache"));

//解析mapper的parameterMap节点

parameterMapElement(context.evalNodes("/mapper/parameterMap"));

//解析mapper的resultMap节点

resultMapElements(context.evalNodes("/mapper/resultMap"));

//解析mapper的sql节点

sqlElement(context.evalNodes("/mapper/sql"));

//使用XMLStatementBuilder的对象解析mapper的select、insert、update、delete节点,

//mybaits会使用MappedStatement.Builder类build一个MappedStatement对象,

//所以mybaits中一个sql对应一个MappedStatement

buildStatementFromContext(context.evalNodes("select|insert|update|delete"));

} catch (Exception e) {

throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);

}

}

configurationElement函数几乎解析了mapper节点下所有子节点,至此mybaits解析了mapper中的所有节点,并将其加入到了Configuration对象中提供给sqlSessionFactory对象随时使用。这里我们需要补充讲一下mybaits是怎么使用XMLStatementBuilder类的对象的parseStatementNode函数借用MapperBuilderAssistant类对象builderAssistant的addMappedStatement解析MappedStatement并将其关联到Configuration类对象的:

[java] view plain copy

public void parseStatementNode() {

//ID属性

String id = context.getStringAttribute("id");

//databaseId属性

String databaseId = context.getStringAttribute("databaseId");

if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {

return;

}

//fetchSize属性

Integer fetchSize = context.getIntAttribute("fetchSize");

//timeout属性

Integer timeout = context.getIntAttribute("timeout");

//parameterMap属性

String parameterMap = context.getStringAttribute("parameterMap");

//parameterType属性

String parameterType = context.getStringAttribute("parameterType");

Class? parameterTypeClass = resolveClass(parameterType);

//resultMap属性

String resultMap = context.getStringAttribute("resultMap");

//resultType属性

String resultType = context.getStringAttribute("resultType");

//lang属性

String lang = context.getStringAttribute("lang");

LanguageDriver langDriver = getLanguageDriver(lang);

Class? resultTypeClass = resolveClass(resultType);

//resultSetType属性

String resultSetType = context.getStringAttribute("resultSetType");

StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));

ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);

String nodeName = context.getNode().getNodeName();

SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));

//是否是select节点

boolean isSelect = sqlCommandType == SqlCommandType.SELECT;

//flushCache属性

boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);

//useCache属性

boolean useCache = context.getBooleanAttribute("useCache", isSelect);

//resultOrdered属性

boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);

// Include Fragments before parsing

XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);

includeParser.applyIncludes(context.getNode());

// Parse selectKey after includes and remove them.

processSelectKeyNodes(id, parameterTypeClass, langDriver);

// Parse the SQL (pre: selectKey and include were parsed and removed)

SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);

//resultSets属性

String resultSets = context.getStringAttribute("resultSets");

//keyProperty属性

String keyProperty = context.getStringAttribute("keyProperty");

//keyColumn属性

String keyColumn = context.getStringAttribute("keyColumn");

KeyGenerator keyGenerator;

String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;

keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);

if (configuration.hasKeyGenerator(keyStatementId)) {

keyGenerator = configuration.getKeyGenerator(keyStatementId);

} else {

//useGeneratedKeys属性

keyGenerator = context.getBooleanAttribute("useGeneratedKeys",

configuration.isUseGeneratedKeys() SqlCommandType.INSERT.equals(sqlCommandType))

? new Jdbc3KeyGenerator() : new NoKeyGenerator();

}

builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,

fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,

resultSetTypeEnum, flushCache, useCache, resultOrdered,

keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);

}

由以上代码可以看出mybaits使用XPath解析mapper的配置文件后将其中的resultMap、parameterMap、cache、statement等节点使用关联的builder创建并将得到的对象关联到configuration对象中,而这个configuration对象可以从sqlSession中获取的,这就解释了我们在使用sqlSession对数据库进行操作时mybaits怎么获取到mapper并执行其中的sql语句的问题。

初看Mybatis 源码 SQL是怎么执行的

Mybatis通过这种方式实现了我们通过getMapper方式得到的Dao接口,可以直接通过接口的没有实现的方法来执行sql。

AuthUserDao mapper = session.getMapper(AuthUserDao.class);

getMapper方法到底做了什么。跟踪getMapper方法,进入到 MapperProxyFactory 类的 newInstance(SqlSession sqlSession) 方法。

@SuppressWarnings("unchecked")

protected T newInstance(MapperProxyT mapperProxy) {

return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);

}

public T newInstance(SqlSession sqlSession) {

final MapperProxyT mapperProxy = new MapperProxyT(sqlSession, mapperInterface, methodCache);

return newInstance(mapperProxy);

}

看过上一篇的例子,我们知道。最后是通过Proxy.newProxyInstance 来实现切入sql的。他的实现在MapperProxy的 invoke 方法里面。看下invoke方法:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if (Object.class.equals(method.getDeclaringClass())) {

return method.invoke(this, args);

}

final MapperMethod mapperMethod = cachedMapperMethod(method);

return mapperMethod.execute(sqlSession, args);

}

简单来说,在invoke里面做了如下事情:

1. 通过我们调用的方法,如本例中的 selectAuthUserByName ,接口名来组合成语句。本例中是 com.mybatis.dao.AuthUserDao.selectAuthUserByName 。其实使用过sqlSession的selectOne(String statmet)之类的语句都知道。这个可以唯一定位到我们在sql映射文件中配置的sql语句

2. 通过返回值类型,定位到的语句的类型。确定最后应该执行的方法。是执行查询、删除、添加、修改等等。

看下mybatis的是如何做的:

public Object execute(SqlSession sqlSession, Object[] args) {

Object result;

if (SqlCommandType.INSERT == command.getType()) {

Object param = method.convertArgsToSqlCommandParam(args);

result = rowCountResult(sqlSession.insert(command.getName(), param));

} else if (SqlCommandType.UPDATE == command.getType()) {

Object param = method.convertArgsToSqlCommandParam(args);

result = rowCountResult(sqlSession.update(command.getName(), param));

} else if (SqlCommandType.DELETE == command.getType()) {

Object param = method.convertArgsToSqlCommandParam(args);

result = rowCountResult(sqlSession.delete(command.getName(), param));

} else if (SqlCommandType.SELECT == command.getType()) {

if (method.returnsVoid() method.hasResultHandler()) {

executeWithResultHandler(sqlSession, args);

result = null;

} else if (method.returnsMany()) {

result = executeForMany(sqlSession, args);

} else if (method.returnsMap()) {

result = executeForMap(sqlSession, args);

} else {

Object param = method.convertArgsToSqlCommandParam(args);

result = sqlSession.selectOne(command.getName(), param);

}

} else {

throw new BindingException("Unknown execution method for: " + command.getName());

}

if (result == null method.getReturnType().isPrimitive() !method.returnsVoid()) {

throw new BindingException("Mapper method '" + command.getName()

+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");

}

return result;

}

可以看到的是,他是通过我们在sql配置文件中的语句类型来判断是执行哪种操作。然后通过返回类型来确定查询是查一条还是查多条记录。最后这种操作的方式,也是回归到了sqlSession中的CRUD的操作的方法。

下面看下,一条sql语句到底是怎么执行的?我们知道Mybatis其实是对JDBC的一个封装。假如我执行

session.update("com.mybatis.dao.AuthUserDao.updateAuthUserEmailByName", test@email.com);

语句,追踪下来,Executor、 BaseStatementHandler等等。在 SimpleExecutor 中有如下代码:

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {

Statement stmt = null;

try {

Configuration configuration = ms.getConfiguration();

StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);

stmt = prepareStatement(handler, ms.getStatementLog());

return handler.update(stmt);

} finally {

closeStatement(stmt);

}

}

1. 首先获取相关配置信息,这个在初始化时,从配置文件中解析而来

2. 新建了一个handler

3. 做了执行statement之前的准备工作。看看准备了些什么,跟踪代码,最后进入了DataSource类的doGetConnection方法,该方法做如下操作:

private Connection doGetConnection(Properties properties) throws SQLException {

initializeDriver();

Connection connection = DriverManager.getConnection(url, properties);

configureConnection(connection);

return connection;

}

private synchronized void initializeDriver() throws SQLException {

if (!registeredDrivers.containsKey(driver)) {

Class? driverType;

try {

if (driverClassLoader != null) {

driverType = Class.forName(driver, true, driverClassLoader);

} else {

driverType = Resources.classForName(driver);

}

// DriverManager requires the driver to be loaded via the system ClassLoader.

//

Driver driverInstance = (Driver)driverType.newInstance();

DriverManager.registerDriver(new DriverProxy(driverInstance));

registeredDrivers.put(driver, driverInstance);

} catch (Exception e) {

throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);

}

}

}

原来是通过prepareStatement 来执行了 我们初始化jdbc的操作。Class.forName DriverManager.getConnection. 这两步是在这里面完成的。

4. 将执行sql的部分交给handler

继续跟踪handler 可以看到SimpleStatementHandler 中。如下执行这个update语句

public int update(Statement statement)

throws SQLException {

String sql = boundSql.getSql();

Object parameterObject = boundSql.getParameterObject();

KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();

int rows;

if (keyGenerator instanceof Jdbc3KeyGenerator) {

statement.execute(sql, Statement.RETURN_GENERATED_KEYS);

rows = statement.getUpdateCount();

keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);

} else if (keyGenerator instanceof SelectKeyGenerator) {

statement.execute(sql);

rows = statement.getUpdateCount();

keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);

} else {

statement.execute(sql);

rows = statement.getUpdateCount();

}

return rows;

}

这边就完成了statement的操作,整个过程就是我们Jdbc的过程。原来真的就是对JDBC的简单封装

GitHub 上有哪些值得推荐的开源电子书

语言无关类

操作系统

鸟哥的Linux私房菜 (简体)

Linux 系统高级编程

The Linux Command Line (中英文版)

Linux 设备驱动 (第三版)

深入分析Linux内核源码

UNIX TOOLBOX

Docker中文指南

Docker —— 从入门到实践

FreeRADIUS新手入门

Mac 开发配置手册

FreeBSD 使用手册

Linux 命令行(中文版)

智能系统

一步步搭建物联网系统

web服务器

Nginx开发从入门到精通 (淘宝团队出品)

版本控制

Git教程 (本文由  @廖雪峰 创作,如果觉得本教程对您有帮助,可以去  iTunes 购买)

git – 简易指南

猴子都能懂的GIT入门

Git 参考手册

Pro Git

Git Magic

GotGitHub

Git Community Book 中文版

Mercurial 使用教程

HgInit (中文版)

沉浸式学 Git

Git-Cheat-Sheet (感谢 @flyhigher139 翻译了中文版)

GitHub秘籍

NoSQL

NoSQL数据库笔谈 (PDF)

Redis 设计与实现

Redis 命令参考

带有详细注释的 Redis 3.0 代码

带有详细注释的 Redis 2.6 代码

The Little MongoDB Book

The Little Redis Book

Neo4j 简体中文手册 v1.8

Neo4j .rb 中文资源

MySQL

MySQL索引背后的数据结构及算法原理

项目相关

持续集成(第二版) (译言网)

让开发自动化系列专栏

追求代码质量

selenium 中文文档

Joel谈软件

约耳谈软体(Joel on Software)

Web

关于浏览器和网络的 20 项须知

前端知识体系

浏览器开发工具的秘密

Chrome 开发者工具中文手册

Chrome扩展开发文档

Grunt中文文档

移动Web前端知识库

正则表达式30分钟入门教程

前端开发体系建设日记

移动前端开发收藏夹

JSON风格指南

HTTP 接口设计指北

前端资源分享(一)

前端资源分享(二)

前端代码规范 及 最佳实践

w3school教程整理

大数据

大数据/数据挖掘/推荐系统/机器学习相关资源

编程艺术

程序员编程艺术

每个程序员都应该了解的内存知识(译)【第一部分】

取悦的工序:如何理解游戏 (豆瓣阅读,免费书籍)

其他

OpenWrt智能、自动、透明翻墙路由器教程

语言相关类 AWK

awk程序设计语言

C/C++

C++ 并发编程指南 (@傅海平ICT)

Linux C编程一站式学习 (宋劲杉, 北京亚嵌教育研究中心)

CGDB中文手册

100个gdb小技巧

100个gcc小技巧

ZMQ 指南

How to Think Like a Computer Scientist (中英文版)

跟我一起写Makefile(PDF)

GNU make中文手册

GNU make 指南

Google C++ 风格指南

C/C++ Primer (by @andycai)

简单易懂的C魔法

Cmake 实践 (PDF版)

C++ FAQ LITE(中文版)

C++ Primer 5th Answers

CSS/HTML

学习CSS布局

通用 CSS 笔记、建议与指导

CSS参考手册

Emmet 文档

前端代码规范 (腾讯alloyteam团队)

Dart

Dart 语言导览

Fortran

Fortran77和90/95编程入门

Java

实时 Java 系列

Apache Shiro 用户指南

使用 Eclipse 和 Java SE 6 创建独立 Web Services 应用程序

第 1 部分: Web Services 服务端应用程序

第 2 部分: Web 服务客户端应用程序

JavaServer Faces 1.2 入门

第 1 部分: 构建基本应用程序

第 2 部分: JSF 生命周期、转换、检验和阶段监听器

用 Eclipse Europa 进行 Web 开发

第 1 部分: Eclipse Java EE

第 2 部分: PHP 开发工具

第 3 部分: Ruby Development Toolkit 和 RadRails

使用 JavaServer Faces 构建 Apache Geronimo 应用程序

第 1 部分: 使用 Eclipse 和 Apache MyFaces Core 构建基本的应用程序

第 2 部分: 在 JavaServer Faces 中使用 Tomahawk

第 3 部分: 使用 ajax4jsf 添加 Ajax 功能

第 4 部分: 使用 Apache Trinidad 组件扩展 JSF

第 5 部分: 将 JSF 应用程序与 Spring 集成

Apache Geronimo 和 Spring 框架

第 1 部分: 开发方法学

第 2 部分: 构建第一个应用程序

第 3 部分: 集成 DAO 与 ORM

第 4 部分: 混合使用 Spring AOP 和 Spring Web Flow

第 5 部分: Spring MVC

第 6 部分: Spring MVC:使用 Web 视图技术

终极 mashup —— Web 服务和语义 Web

第 1 部分: 使用与组合 Web 服务

第 2 部分: 管理 Mashup 数据缓存

第 3 部分: 理解 RDF 和 RDFs

第 4 部分: 创建本体

第 5 部分: 切换 Web 服务

Jersey 2.x 用户指南

MyBatis中文文档

JavaScript

Google JavaScript 代码风格指南

Airbnb JavaScript 规范

JavaScript 标准参考教程(alpha)

Javascript编程指南 (源码)

javascript 的 12 个怪癖

JavaScript 秘密花园

JavaScript核心概念及实践 (PDF) (此书已由人民邮电出版社出版发行,但作者依然免费提供PDF版本,希望开发者们去购买,支持作者)

《JavaScript 模式》翻译,此书中文版有售,但是纸质书翻译的还没有这个版本翻译的好

命名函数表达式探秘 (注:原文由为之漫笔翻译,原始地址无法打开,所以此处地址为我博客上的备份)

学用 JavaScript 设计模式 (开源中国)

深入理解JavaScript系列

ECMAScript 6 入门 (作者:阮一峰)

jQuery

jQuery 解构

简单易懂的JQuery魔法

How to write jQuery plugin

Node.js

Node入门

七天学会NodeJS

Nodejs Wiki Book (繁体中文)

express.js 中文文档

koa 中文文档

使用 Express + MongoDB 搭建多人博客

Express框架

nodejs文档

Node.js 包教不包会

Learn You The Node.js For Much Win! (中文版)

Node debug 三法三例

underscore.js

Underscore.js中文文档

backbone.js

backbone.js入门教程 (PDF)

Backbone.js入门教程第二版

Developing Backbone.js Applications(中文版)

AngularJS

AngularJS最佳实践和风格指南

AngularJS中译本

AngularJS入门教程

构建自己的AngularJS

在Windows环境下用Yeoman构建AngularJS项目

zepto 简明中文手册

Sea.js

Hello Sea.js

CoffeeScript

CoffeeScript Cookbook

The Little Book on CoffeeScript中文版

ExtJS

Ext4.1.0 中文文档

Chrome扩展及应用开发

JavaScript入门教程

PHP

PHP调试技术手册(PDF)

XDebug 2中文手册(译) (CHM)

PHP之道

PHP 最佳实践

PHP安全最佳实践

深入理解PHP内核

PHP扩展开发及内核应用

CodeIgniter 用户指南

Laravel4 中文文档

Laravel 入门

Symfony2中文文档 (未译完)

Phalcon中文文档(翻译进行中)

YiiBook几本Yii框架的在线教程

简单易懂的PHP魔法

swoole文档及入门教程

iOS

iOS开发60分钟入门

iOS7人机界面指南

Google Objective-C Style Guide 中文版

iPhone 6 屏幕揭秘

Apple Watch开发初探

马上着手开发 iOS 应用程序

网易斯坦福大学公开课:iOS 7应用开发字幕文件

Android

Android Design(中文版)

Google Android官方培训课程中文版

Android学习之路

Python

小白的Python教程

简明Python教程

零基础学Python

Python 2.7 官方教程中文版

Python 3.3 官方教程中文版

深入 Python 3

PEP8 Python代码风格规范

Google Python 风格指南 中文版

Python入门教程 (PDF)

Python的神奇方法指南

笨办法学 Python (PDF版下载)

Django 文档中文版

Django 最佳实践

The Django Book 中文版

web.py 0.3 新手指南

Web.py Cookbook 简体中文版

Dive Into Python 中文版

Bottle 文档中文版 (需翻墙)

Flask 文档中文版

Jinja2 文档中文版

Werkzeug 文档中文版

Flask之旅

Introduction to Tornado 中文翻译

Python自然语言处理中文版 (感谢陈涛同学的翻译,也谢谢  @shwley 联系了作者)

Python 绘图库 matplotlib 官方指南中文翻译

Scrapy 0.25 文档

ThinkPython

Ruby

Ruby 风格指南

Rails 风格指南

笨方法学 Ruby

Ruby on Rails 指南

Ruby on Rails 实战圣经

Ruby on Rails Tutorial 原书第 2 版 (本书网页版免费提供,电子版以 PDF、EPub 和 Mobi 格式提供购买,仅售 9.9 美元)

编写Ruby的C拓展

Ruby 源码解读

Shell

Shell脚本编程30分钟入门

Go

Go编程基础

Go入门指南

学习Go语言 (PDF)

Go Web 编程 (此书已经出版,希望开发者们去购买,支持作者的创作)

Go实战开发 (当我收录此项目时,作者已经写完第三章,如果读完前面章节觉得有帮助,可以给作者捐赠,以鼓励作者的继续创作)

Network programming with Go 中文翻译版本

Groovy

实战 Groovy 系列

LaTeX

一份其实很短的 LaTeX 入门文档

一份不太简短的 LATEX 2ε 介绍 (PDF版)

LISP

ANSI Common Lisp 中文翻译版

Lua

Lua编程入门

Haskell

Real World Haskell 中文版

R

R语言忍者秘笈

Scala

Scala课堂 (Twitter的Scala中文教程)

Effective Scala(Twitter的Scala最佳实践的中文翻译)

Scala指南

Swift

The Swift Programming Language 中文版

Perl

Modern Perl 中文版

Perl 程序员应该知道的事

Prolog

笨办法学Prolog

Vim中文文档

Vimscript

笨方法学Vimscript 中译本

Vim中文文档

读书笔记及其它 读书笔记

编译原理(紫龙书)中文第2版习题答案

把《编程珠玑》读薄

Effective C++读书笔记

Golang 学习笔记、Python 学习笔记、C 学习笔记 (PDF)

Jsoup 学习笔记

学习笔记: Vim、Python、memcached

图灵开放书翻译计划–C++、Python、Java等

蒂姆·奥莱利随笔 (由译言网翻译,电子版免费)

Octave 入门 (PDF版)

SICP 解题集

精彩博客集合

正则表达式简明参考

发表评论

评论列表

  • 北槐婳悕(2022-07-04 22:37:15)回复取消回复

    ow to Think Like a Computer Scientist (中英文版)跟我一起写Makefile(PDF)GNU make中文手册GNU make 指南Google C++ 风格指南C/C++ Primer (