Giter Club home page Giter Club logo

mybatis-book's Introduction

Mybatis源码深度解析

Codacy Badge Total lines Build Status

书籍封面

书籍封面

图书目录

前言 4
第1篇 Mybatis3源码 7
第1章 搭建Mybatis源码环境 7
1.1 Mybatis3简介 7
1.2 环境准备 7
1.3 获取Mybatis源码 8
1.4 导入Mybatis源码到IDE 10
1.5 HSQLDB数据库简介 13
1.6 本章小结 16
第2章 JDBC规范详解 17
2.1 JDBC API简介 17
2.1.1 建立数据源连接 18
2.1.2 执行SQL语句 19
2.1.3 处理SQL执行结果 19
2.1.4 使用JDBC操作数据库 20
2.2 JDBC API中的类与接口 21
2.2.1 java.sql包详解 21
2.2.2 javax.sql包详解 24
2.3 Connection详解 28
2.3.1 JDBC驱动类型 29
2.3.2 java.sql.Driver接口 30
2.3.3 Java SPI机制简介 31
2.3.4 java.sql.DriverAction接口 33
2.3.5 java.sql.DriverManager类 34
2.3.5 javax.sql.DataSource接口 35
2.3.6 使用JNDI API增强应用可移植性 36
2.3.7 关闭Connection对象 39
2.4 Statement详解 39
2.4.1 java.sql.Statement接口 40
2.4.2 java.sql.PreparedStatement接口 44
2.4.3 java.sql.CallableStatement接口 48
2.4.4 获取自增长的键值 49
2.5 ResultSet详解 50
2.5.1 ResultSet类型 50
2.5.2 ResultSet并行性 51
2.5.3 ResultSet可保持性 51
2.5.4 ResultSet属性设置 52
2.5.5 ResultSet游标移动 52
2.5.6 修改ResultSet对象 53
2.5.7 关闭ResultSet对象 55
2.6 DatabaseMetaData详解 55
2.6.1 创建DatabaseMetaData对象 56
2.6.2 获取数据源基本信息 56
2.6.3 获取数据源支持特性 57
2.6.5 获取数据源限制 58
2.6.7 获取SQL对象及属性 58
2.6.8 获取事务支持 59
2.7 JDBC事务 59
2.7.1 事务边界与自动提交 59
2.7.2 事务隔离级别 59
2.7.3 事务中保存点 61
2.8 本章小结 62
第3章 Mybatis常用工具类 63
3.1 使用SQL类生成语句 63
3.2 使用ScriptRunner执行脚本 69
3.3 使用SqlRunner操作数据库 72
3.4 MetaObject详解 76
3.5 MetaClass详解 77
3.6 ObjectFactory详解 79
3.7 ProxyFactory详解 80
3.8 本章小结 81
第4章 Mybatis核心组件介绍 82
4.1 使用Mybatis操作数据库 82
4.2 Mybatis核心组件 86
4.3 Configuration详解 88
4.4 Executor详解 94
4.5 MappedStatement详解 96
4.6 StatementHandler详解 99
4.7 TypeHandler详解 100
4.9 ParameterHandler详解 104
4.9 ResultSetHandler详解 105
4.10 本章小结 106
第5章 SqlSession创建过程 108
5.1 XPath方式解析XML文件 108
5.2 Configuration实例创建过程 111
5.3 SqlSession实例创建过程 115
5.4 本章小结 116
第6章 SqlSession执行Mapper过程 118
6.1 Mapper接口注册过程 118
6.2 MappedStatement注册过程 122
6.3 Mapper方法调用过程详解 128
6.4 SqlSession执行Mapper过程 134
6.5 本章小结 139
第7章 Mybatis缓存 139
7.1 Mybatis缓存的使用 139
7.2 Mybatis缓存实现类 140
7.3 Mybatis一级缓存实现原理 144
7.4 Mybatis二级缓存实现原理 147
7.5 Mybatis使用Redis缓存 152
7.6 本章小结 154
第8章 Mybatis日志实现 155
8.1 Java日志体系 155
8.2 Mybatis日志实现 159
8.3 本章小结 165
第9章 动态SQL实现原理 166
9.1 动态SQL的使用 166
9.2 SqlSource与BoundSql详解 168
9.3 LanguageDriver详解 171
9.4 SqlNode详解 174
9.5 动态SQL解析过程 179
9.6 从源码角度分析#{}和${}区别 189
9.7 本章小结 193
第10章 Mybatis插件实现原理 194
10.1 Mybatis插件实现原理 194
10.2 自定义一个分页插件 203
10.3 自定义慢SQL统计插件 211
10.4 本章小结 212
第11章 Mybatis级联映射与懒加载 214
11.1 Mybatis级联映射详解 214
11.1.1 准备工作 214
11.1.2 一对多关联映射 217
11.1.3 一对一关联映射 219
11.1.4 Discriminator详解 221
11.2 Mybatis懒加载机制 223
11.3 Mybatis级联映射实现原理 224
11.3.1 ResultMap详解 224
11.3.2 ResultMap解析过程 225
11.3.3 级联映射实现原理 231
11.4 懒加载实现原理 238
11.5 本章小结 243
第2篇 Mybatis Spring源码 245
第12章 Mybatis与Spring整合案例 245
12.1 准备工作 245
12.2 Mybatis与Spring整合 246
12.3 用户注册案例 248
12.4 本章小结 251
第13章 Mybatis Spring实现原理 252
13.1 Spring中的一些概念 252
13.2 Spring容器启动过程 255
13.3 Mapper动态代理对象注册过程 256
13.4 Mybatis整合Spring事务管理 260
13.5 本章小结 264

内容概要

本书主要分为两个篇章,第一篇章为Mybatis3源码篇,从第1章至11章,主要介绍Mybatis框架各个特性的实现原理。第二篇章为Mybatis Spring源码篇,主要介绍Mybatis框架与Spring框架整合原理。

📚 第一章 搭建Mybatis源码环境

主要介绍如何搭建Mybatis源码调试环境,包括Mybatis框架源码获取途径,如何导入集成开发工具,如何运行Mybatis源码中自带的测试用例。

📚 第二章 JDBC规范详解

Mybatis框架是对JDBC轻量级的封装,熟练掌握JDBC规范有助于理解Mybatis框架实现原理,本章详细介绍JDBC规范相关细节,已经全面掌握JDBC规范的读者可以跳过该章节。

📚 第三章 Mybatis常用工具类

介绍Mybatis框架中常用的工具类,避免读者对这些工具类的使用不熟悉,而导致对框架主流程理解的干扰,这些工具类包括MetaObject、ObjectFactory、ProxyFactory等。

📚 第四章 Mybatis核心组件介绍

介绍Mybatis的核心组件,包括Configuration、SqlSession、Executor、MappedStatement等,本章详细介绍了这些组件的作用及Mybatis执行SQL语句的核心流程。

📚 第五章 SqlSession创建过程

主要介绍SqlSession组件的创建过程,包括Mybatis框架对XPath方式解析XML封装的工具类,Mybatis主配置文件解析生成Configuration对象的过程。

📚 第六章 SqlSession执行Mapper过程

本章介绍Mapper接口注册过程,SQL配置转换为MappedStatement对象并注册到Configuration对象的过程。除此之外,本章还介绍了通过SqlSession执行Mapper的过程。

📚 第七章 Mybatis缓存

本章首先介绍了Mybatis一级缓存和二级缓存的使用细节,接着介绍了一级缓存和二级缓存的实现原理,最后介绍了Mybatis如何整合Redis作为二级缓存。

📚 第八章 Mybatis日志实现

基于Java语言的日志框架比较多,比较常用的有Logback、Log4j等,本章介绍了Java的日志框架发展史,并介绍了这些日志框架之间的关系。最后,本章介绍了Mybatis自动查找日志框架的实现原理。

📚 第九章 动态SQL实现原理

本章主要介绍Mybatis动态SQL的使用,动态SQL配置转换为SqlSource对象的过程,以及动态SQL的解析原理,最后从源码的角度分析动态SQL配置中#{}和${}参数占位符的区别。

📚 第十章 Mybatis插件实现原理

本章介绍了Mybatis插件的实现原理,并以实际的案例介绍了如何自定义Mybatis插件。本章中实现了两个Mybatis插件,分别为分页查询插件和慢SQL统计插件。

📚 第十一章 Mybatis级联映射与懒加载

本章介绍了Mybatis中的一对一、一对多级联映射和懒加载机制的使用细节,并介绍了级联映射和懒加载的实现原理。

📚 第十二章 Mybatis与Spring整合案例

本章中以一个用户注册RESTful接口案例,介绍了Mybatis框架与Spring框架整合的最佳实践。

📚 第十三章 Mybatis Spring实现原理

本章介绍了Spring框架中的一些核心概念,并介绍了Spring IoC容器的使用过程。接着介绍了Mybatis和Spring整合后,动态代理产生的Mapper对象是如何与Spring Ioc容器进行关联的,最后介绍了Mybatis整合Spring事务管理的实现原理。

读者交流群

企鹅群:1055227297

mybatis-book's People

Contributors

jiangrongbo avatar jidiboy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

mybatis-book's Issues

对《MyBatis 3源码深度解析》的一些读后感与建议

江老师您好:
最近阅读了您著作的《MyBatis 3源码深度解析》这本书,收获颇丰。在阅读“第13章 MyBatis Spring的实现原理”的过程中,有一些读后感与建议与您分享下。

您在“13.3 Mapper动态代理对象注册过程”中分析,Mapper是通过

  public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    ...
    public T getObject() throws Exception {
      return getSqlSession().getMapper(this.mapperInterface);
    }
    public boolean isSingleton() {
      return true;
    }
    ...
  }

进行注册的,该FactoryBean是单例的,因此Spring只会为每个Mapper创建一次动态代理对象;
而在MyBatis单独使用过程中,都是在方法作用域里创建新的SqlSession和Mapper的动态代理对象。

MyBatis官方对SqlSession和Mapper作用域的说明如下:
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
映射器是一些绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的。虽然从技术层面上来讲,任何映射器实例的最大作用域与请求它们的 SqlSession 相同。但方法作用域才是映射器实例的最合适的作用域。

由此就有一些疑惑:
1、mybatis-spring如何保证SqlSession是线程安全的?
2、mybatis与spring集成后,mapper的动态代理对象的作用域是应用级别的,会不会存在问题?

带着这两个问题阅读源码分析:
1、mybatis-spring通过MapperFactoryBean注册Mapper的动态代理对象时,会注入SqlSessionTemplate,该注入是在MapperFactoryBean的父类中实现的

public abstract class SqlSessionDaoSupport extends DaoSupport {

  private SqlSession sqlSession;

  private boolean externalSqlSession;

  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (!this.externalSqlSession) {
      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }
  }

  public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
    this.sqlSession = sqlSessionTemplate;
    this.externalSqlSession = true;
  }

因为使用的是setter注入,因此需要设置自动注入模式,见org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions方法:
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
mybatis-spring能够保证SqlSession是线程安全,主要是其在SqlSessionTemplate的实例化过程中,为SqlSession创建了一个动态代理对象,并作为自己的实例变量sqlSessionProxy的引用

  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {

    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
    notNull(executorType, "Property 'executorType' is required");

    this.sqlSessionFactory = sqlSessionFactory;
    this.executorType = executorType;
    this.exceptionTranslator = exceptionTranslator;
    this.sqlSessionProxy = (SqlSession) newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class },
        new SqlSessionInterceptor());
  }

其中关键之处在于SqlSessionInterceptor

  private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(
          SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType,
          SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
          sqlSession = null;
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }

从SqlSessionInterceptor的invoke方法可以看出,通过其创建的动态代理对象在执行方法过程中都会先获取SqlSession,然后再使用该SqlSession执行具体的方法,该SqlSession是借助TransactionSynchronizationManager的ThreadLocal来保证线程安全的。
2、与Spring集成后,所有的Mapper都是在容器初始化的时候就创建了相应的动态代理对象,在执行mapper的方法时,代理给SqlSessionTemplate执行的,而SqlSessionTemplate又代理给了sqlSessionProxy:

  public <E> List<E> selectList(String statement, Object parameter) {
    return this.sqlSessionProxy.<E> selectList(statement, parameter);
  }

sqlSessionProxy执行相应方法的时候会获取一个线程安全的SqlSession,然后通过该线程安全的SqlSession执行相应的方法,所以Mapper虽然不是方法级别的作用域,但是能够保证SqlSession是线程安全的;
单独使用MyBatis的时候,保证mapper是方法级别的作用域的目的也是因为要保证SqlSession是线程安全的。
3、单独使用MyBatis时,也可以使用SqlSessionManager来实现线程安全的SqlSession,同TransactionSynchronizationManager一样也是使用LocalThread来保证SqlSession的线程安全,该类的设计思路与SqlSessionTemplate相似。

感受:
本人是在对Spring及MyBatis源码有一定研读的基础上阅读的本书,所以能够根据问题分析源码为自己解惑。但是如果读者的源码阅读经验较少时,那么对该章节“MyBatis Spring的实现原理”的理解就可能存在困惑而不得解。因此,建议江老师对这部分的阐述可以更加详细点。

以上为个人建议与观点,只为《MyBatis 3源码深度解析》这本书能够给读者提供更多的帮助,如有冒犯请见谅。

希望能出个 spring 的书

江老师,您好,我看完了《MyBatis 3源码深度解析》,觉得您写的出书,非常非常好。我看了半个月,才能勉强跟上您书里的节奏。希望能出一个 spring 的书。期待您的新书。

flushCache的问题

在书中的132页, 有提到这样一段话:
另外,还可以通过flushCache属性指定Mapper执行后是否刷新缓存

江老师, 这里有一点疑问。

在mybatis的代码中有这样一段:

org.apache.ibatis.executor.BaseExecutor#query(...){
   if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
//省略... 从一级缓存中获取, 或者从数据库中查询的代码
}

这里并不是在mapper执行后是否刷新缓存, 而是在mapper执行前清理缓存。

关于这个问题,也可能是我这边场景的实现有问题, 希望江老师看一下。

图书勘误

江老师您好,在阅读《MyBaties3源码深度解析》中,我发现了一个小错误。第123页中,倒数第三行的SortedMap的句柄声明有误,我看源码中是names,但是江老师您这边的是map。

mybatis日志实现流程

这里我框出来的未指定是不是有问题,自动查找的逻辑是在静态代码块的,所以在Configuration里调用setLogImpl的方法时,LogFactory是不是先执行的静态代码块来自动查找日志实现,然后在读取主配置文件的logimpl吗?
日志2
日志

第一章中有关mybatis的git repo路径勘误

您好,最近正在学习mybatis,购买了您的《Mybatis3源码深度解析》,目前正在学习中。第一章您有提到mybatis的三个项目:mybatis-3,spring和parent,书中写的路径两个都为parent.git(应该为一个是mybatis-3.git和一个parent.git)和一个spring.git,不知道是否是印刷的错误。

错别字勘误

第3章 MyBatis常用工具类
3.2 使用ScriptRunner执行脚本

// 脚本文件中 SQL语句的分隔符,默认为 ;
private String delimiter = DEFAULT_DELIMITER;
// 是否支持SQL语句分割符,单独占一行
private boolean fullLineDelimiter;

两行注释中 第一行使用“分隔符” 第二行使用“分割符”
有一行应该是错别字

图书上hsqlbd的依赖添加有问题

这是你demo上使用的hsqldn依赖:

<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>2.4.1</version>
    <scope>test</scope>
</dependency>

这是书本上hsqldb的依赖:

<dependency>
    <groupId>hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>1.8.0.7</version>
    <scope>test</scope>
</dependency>

Chaper4 UserMapper.xml文件

你好,这个文件
chapter04/src/main/resources/com/blog4java/mybatis/example/mapper/UserMapper.xml

里面的resultType应该是com.blog4java.mybatis.example.entity.UserEntity,而不是User。否则MybatisExample.java的单测跑不过·

二级缓存问题

org.apache.ibatis.builder.xml.XMLConfigBuilder#settingsElement 这个方法中有这么一行代码:
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
意思不就是默认开启二级缓存的吗?《Mybatis3源码深度解析》,7.4章节说默认关闭的,是不是有点问题?

(PS:QQ群找不到啊,企鹅群:1055227297,是这个吗?搜不到~~ 我QQ 1032817876 )
QQ截图20200502111838

希望能出一本tomcat源码的书

江老师您好,因为之前稍微看过spring的源码,所以这个我两天就看完了,觉得写的超级好,,所以想请求您能否再写一本关于tomcat源码的书?真的好期待!

SqlSession是Executor组件的外观 如何理解?

在书中4.2中:
SqlSession:SqlSession是MyBatis提供的面向用户的API,表示和数据库交互时的会话对象,用于完成数据库的增删改查功能。SqlSession是Executor组件的外观,目的是对外提供易于理解和使用的数据库操作接口。
关于 SqlSession是Executor组件的外观 这句话如何理解?

项目maven依赖过期

mybatis-book 项目中的pom.xml 的依赖

org.mybatis
mybatis
3.5.0-SNAPSHOT

依赖已经过期。 官网已经发布该版本正式版
建议将 3.5.0-SNAPSHOT
改成 3.5.0

图书勘误

江老师您好,最近在阅读您写的《MyBatis 3源码深度解析》,对于本人理解MyBatis源码提供了很大的帮助。阅读过程中,发现书上有个小错误,您核对下是否有误。
6.3 Mapper方法调用过程详解
原文:
如上面的代码所示,MethodSignature构造方法中只做了3件事情:(1)获取Mapper方法的返回值类型,具体是哪种类型,通过boolean类型的属性进行标记。例如,当返回值类型为void时,returnsVoid属性值为true,当返回值类型为List时,将returnsMap属性值设置为true。MethodSignature类中标记Mapper返回值类型的属性如下:
修正:
当返回值类型为List时,将returnsMap属性值设置为true --> 当返回值类型为List时,将returnsMany属性值设置为true
1593269666(1)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.