Java进阶-MyBatis

2022-05-16  本文已影响0人  GIT提交不上

一、参考资料

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);
MyBatis配置文件加载.png

3.2 Mapper.xml的解析

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

四、缓存

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

  一级缓存失效的情景:

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

BaseExecutor#query
protected PerpetualCache localCache;
CachingExecutor#query

private final TransactionalCacheManager tcm = new TransactionalCacheManager();

public <E> List<E> 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<E> list = (List<E>) 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增强类-动态代理。

六、Spring整合MyBatis

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!-- MyBatis全局配置文件 -->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <property name="typeAliasesPackage" value="com.linkedbear.mybatis.entity"/>
</bean>

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

public class SqlSessionFactoryBean
       implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {

   // ......

   private Resource configLocation;

   private Configuration configuration;

  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

  selectList的整体调用时序图:

image.png image.png
上一篇下一篇

猜你喜欢

热点阅读