Mybatis整合Spring实现事务管理的源码分析

一:前言

没有完整看完,但是看到了一些关键的地方,这里做个记录,过程会有点乱,以后逐渐补充最终归档为完整流程;相信看过框架源码的都知道过程中无法完全确定是怎样的流程,毕竟不可能全部都去测试一遍

,但是看的过程中灵感的显现很重要(就是直觉知道接下来的步骤是什么应该是什么之类的,但是这个自觉是猜的而非蒙的,即过程里是有往会递推看到了一些关键点的而不是抛色子来确定是哪个子类)

,因此自己写的时候也无法将看的过程里产生的想法写得很细,过程也有点跳,如果大家有疑问最好自己去验证(方式就是搜索然后看哪里调用了这样一步步看下去就行,有些小技巧就是如果是public那么一般都是由外部类调用[入口],如果是protected却没实现

说明在之类里有实现,如果已经实现说明此方法在父类里会被调用,如果是private那么肯定在当前类会被调用);

二:重要类或方法

1)对于Mybatis

1.org.apache.ibatis.executor.Executor接口,有大概BatchExecutor/ReuseExecutor/SimpleExecutor三个子类有共同的父类BaseExecutor,它是DefaultSqlSession类的组件,sqlSession对象的如selectOne实际上是由executor执行的;

2.org.apache.ibatis.transaction.Transaction接口,它的实现类有多个,但是每个实现类里都有DataSource属性用于产生数据源和数据库服务交互;

3.SpringManagedTransaction是支持Spring管理Mybatis事务的关键;

4.DefaultSqlSessionFactory

5.DefaultSqlSession

它们之间的重要关系:sqlsession里有executor;executor里有transaction对象;transaction里有datasource;

流程:sqlsession执行代码委托为executor执行,executor里通过transaction获得connection;而transaction又通过判断threadlocalmap里是否有ConnectionHolder对象;如果没有则通过datasource获得一个,否则返回存在threadlocalmap里的;

三:执行流程

如:sqlSession.selectOne执行流程:

3.1selectOne最终转到selectList;

3.2调用sqlsession的属性executor.query方法执行;

3.3在BaseExecutor的query方法里执行这一句:list = this.queryFromDatabase(ms , parameter, rowBounds , resultHandler , key , boundSql) ; ,因此这一句代码很关键;

3.4接着看里面有 this.doQuery(ms , parameter , rowBounds , resultHandler , boundSql) ; 方法;

3.5接着看SimpleExecutor的doQuery方法(看源码很多时候是靠即时的灵感,比较难完整描述看时的思路和过程);

补充开始:1.接着看stmt = this.prepareStatement(handler , ms.getStatementLog()) ; ,很重要,因为statement执行sql语句也是通过它内部的connection对象来执行的;

2.看Connection connection = this.getConnection(statementLog) ; ,接着看里面有:Connection connection = this.transaction.getConnection() ; 重要重要 ,transaction终于在执行sql的过程里出现了;

3.整合Spring的情况下通过本文的上下文知道此transaction是SpringManagedTransaction对象;

4.接着看SpringManagedTransaction的 this.openConnection() ;有代码:

this.connection = DataSourceUtils.getConnection(this.dataSource);
        this.autoCommit = this.connection.getAutoCommit();
        this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);

5.我们看DataSourceUtils.getConnection( this .dataSource);,然后转到doGetConnection方法里有代码:

ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);
if(conHolder == null ...)
{通过dataSource获得一个新的connection}
else{
conHolder.getConnection();  //return一个在threadlocalmap里的connection对象;
}

注意,上上面的DataSourceUtils和这里当 TransactionSynchronizationManager及ConnectionHolder 是spring里的类不是mybatis的,里面的threadlocal对象都是静态的,因此mybatis可以获得spring中放在threadlocalmap的connectionholder对象;

而spring是否产生connectionholder以及是否放到threadlocalmap里是根据txAdvice策略来的;

补充结束;

3.6接着看handler.query(stmt , resultHandler) ; 然后可以挑RoutingStatementHandler的这个方法看;

3.7会委托给其它handler处理,这里可暂定为PreparedStatementHandler类;

3.8看到ps.execute() ; ,后面没什么好看了就是jdk中通过stmt执行sql的方式,这里关键的是stmt里的connection是什么;

四:和Spring整合过程中重要步骤

1.配置了 org.mybatis.spring.SqlSessionFactoryBean ,默认情况下它内部的transactionFactory属性是SpringManagedTransactionFactory对象(如果不想Spring来管理事务则可以主动指定sqlSessionFactoryBean的transactionFactory为别的类);

2.SqlSessionFactoryBean的sqlSessionFactory的configuration的environment里保存了transactionFactory对象为SpringManagedTransactionFactory对象,这一步很重要;

3.我们来看DefaultSqlSessionFactory的openSessionFromDataSource方法(真正获得sqlSession对象的地方),里面有代码

Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);

注意:execType默认对应的是SimpleExecutor,且这个executor里保存了SpringManagedTransactionFactory产生的SpringManagedTransaction对象,这里先明确一下;

4.上面已经明确了sqlSession执行语句是委托为exector来执行的;后面的步骤和三里的一致了就不赘述了;

五:Spring里事务管理的重要类和方法

1. org.springframework.transaction.interceptor.TransactionInterceptor ,极其重要,这个是当执行pointcut方法时将会由这个事务拦截器根据 < tx :attributes> 配置的propagation做一些额外处理(是一个around),包括是否需要产生connection对象和将这个connection对象的autoCommit设置为什么值(SpringManagedTransaction的 this.openConnection() ;会用到此值 ),比如 REQUIRED 就会先判断threadlocalmap里是否有connectionholder,有不做预处理没有则通过datasource获取connection并设置为autoCommit为false,然后通过

connectionholer包装此connection并set到threalocalmap里;

2. org.springframework.jdbc.datasource.DataSourceTransactionManager ,极其重要,是spring用来根据propagation策略来执行不同的逻辑的重要组件(在TransactionInterceptor的invoke方法里执行);

3.TxNamespaceHandler用来处理名称空间为tx的元素;

4.TxAdviceBeanDefinitionParser用来解析<tx:advice元素,通过doParse处理;

5.NameMatchTransactionAttributeSource,极其重要,存储了<tx:attributes里配置的策略供TransactionInterceptor使用;

补充:如果要看懂spring的事务管理,可以从TransactionInterceptor的invoke方法实现开始看,这个是入口函数,而内部用到的ConnectionHolder则是和Mybatis有交互的类;

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/qq_41699100/article/details/84261667
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞