Java进阶-MyBatis

一、参考资料

MyBatis官网
玩转 MyBatis:深度解析与定制
Mybatis介绍
为什么建议框架源码学习从Mybatis开始

二、整体结构

image.png

三、配置文件

https://mybatis.org/mybatis-3/zh/configuration.html#settings

3.1 配置文件加载

InputStream xml = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(xml);
  • 通过ClassLoader获取到全局配置文件的二进制流
  • XMLConfigBuilder构建SqlSessionFactory
MyBatis配置文件加载.png

3.2 Mapper.xml的解析

XMLConfigBuilder#parseConfiguration
mapperElement(root.evalNode("mappers"));
Mapper.xml解析.png

四、缓存

  一级缓存基于SqlSession,可以直接创建SqlSessionFactory,并从中开启一个新的SqlSession,默认情况下它会自动开启事务。

  一级缓存失效的情景:

  • 跨SqlSession的一级缓存不共享
  • 两次相同的查询间有DML操作
  • 手动清空了一级缓存

  SpringFramework/SpringBoot整合MyBatis后,Service方法中没有开启事务时,每次调用Mapper查询数据时,底层都会创建一个全新的SqlSession去查数据库。

BaseExecutor#query
protected PerpetualCache localCache;
  • SqlSession关闭时,一级缓存的数据进入二级缓存
  • 二级缓存中有数据时,直接取出,不会预先开启Connection
  • 二级缓存基于nameSpace级别
CachingExecutor#query

private final TransactionalCacheManager tcm = new TransactionalCacheManager();

public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, 
                         ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    Cache cache = ms.getCache();
    if (cache != null) {
        flushCacheIfRequired(ms);
        if (ms.isUseCache() && resultHandler == null) {
            ensureNoOutParams(ms, boundSql);
            List list = (List) tcm.getObject(cache, key);
            if (list == null) {
                list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                tcm.putObject(cache, key, list); // issue #578 and #116
            }
            return list;
        }
    }
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

   TransactionalCacheManager:二级缓存应该是基于事务提交的,只有事务提交后,数据库的数据确定没有问题,这个时候SqlSession中的一级缓存数据也是准确的,这样才能把一级缓存的数据写入到二级缓存中。

   二级缓存在写入时已经执行了一次基于jdk的序列化动作,每次从二级缓存取数据时,会再执行一次反序列化,将字节数组转为缓存数据对象。

五、日志

  Logger增强类-动态代理。

  • PreparedStatementLogger
  • ConnectionLogger
  • ResultSetLogger

六、Spring整合MyBatis


    
    
    
    

  SqlSessionFactoryBean:只负责mapper.xml的处理。

public class SqlSessionFactoryBean
       implements FactoryBean, InitializingBean, ApplicationListener {

   // ......

   private Resource configLocation;

   private Configuration configuration;
  • 几乎可以代替MyBatis全局配置文件
  • 可以传入全局配置文件,供MyBatis解析和处理
  • 代替MyBatis处理数据源和事务工厂
  • 只处理和解析mapper.xml

  MapperScannerConfigurer:扫描Mapper接口。

public class MapperScannerConfigurer
        implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {

    private SqlSessionFactory sqlSessionFactory;

    private SqlSessionTemplate sqlSessionTemplate;

    private String sqlSessionFactoryBeanName;

    private String sqlSessionTemplateBeanName;

  ClassPathMapperScanner,它会执行包扫描的动作,并且将扫描到的Mapper接口都收集起来,构造成MapperFactoryBeanMapper,注入到SqlSessionFactory和SqlSessionTemplate。

七、生命周期

  整体结构:

image.png

  Executor类结构:

image.png
  • CRUD操作
  • 事务控制和获取
  • 二级缓存的控制
  • 延迟加载

  selectList的整体调用时序图:

image.png
  • SqlSource中传入参数,返回BoundSql的过程,会将动态SQL解析转化为可以执行的带占位符的SQL语句
image.png

你可能感兴趣的:(Java进阶-MyBatis)