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有交互的类;
Mybatis整合Spring实现事务管理的源码分析的更多相关文章
- 【spring源码学习】spring的事务管理的源码解析
[一]spring事务管理(1)spring的事务管理,是基于aop动态代理实现的.对目标对象生成代理对象,加入事务管理的核心拦截器==>org.springframework.transact ...
- Spring Environment(二)源码分析
Spring Environment(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...
- Spring Boot 揭秘与实战 源码分析 - 工作原理剖析
文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...
- Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机
文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多”开箱即用“的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内 ...
- Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析
一.背景 前面详解了实现Spring事务的两种方式的不同实现:编程式事务和声明式事务,对于配置都使用到了xml配置,今天介绍Spring事务的注解开发,例如下面例子: 配置类:注册数据源.JDBC模板 ...
- spring事务概念与获取事务时事务传播行为源码分析
一.事务状态:org.springframework.transaction.TransactionStatus isNewTransaction 是否是新事务 hasSavepoint 是否有保存点 ...
- Spring Security(四) —— 核心过滤器源码分析
摘要: 原创出处 https://www.cnkirito.moe/spring-security-4/ 「老徐」欢迎转载,保留摘要,谢谢! 4 过滤器详解 前面的部分,我们关注了Spring Sec ...
- MyBatis(六):SqlSession执行源码分析
SqlSession执行源码分析 针对以下代码 public class MybatisUtils { private static SqlSessionFactory sqlSessionFacto ...
- Spring Cloud Eureka服务注册源码分析
Eureka是怎么work的 那eureka client如何将本地服务的注册信息发送到远端的注册服务器eureka server上.通过下面的源码分析,看出Eureka Client的定时任务调用E ...
随机推荐
- GitChat招募IT类写作作者
GitChat是一个移动端的IT知识.技术分享平台,于2017.10和CSDN合并,成为其旗下独立品牌. 我们正在寻求有互联网基因的人来一起分享IT人员的关切,诚挚邀请您来做一次分享(让IT类文章变现 ...
- vue 手机端开发 小商铺 添加购物车 以及结算 功能
这个功能绕了我一天!!! 对 就是这个功能 一系列相关联的 四处相关联 现在加班 没时间更 过两天在更
- CentOS 7 Redis安装配置
1.获取Redis压缩包: wget http:.tar.gz 2.解压测试: mv 到 /usr/local/ tar .tar cd redis 3.使用make测试编译: make 这里可能会出 ...
- java 零基础搭建dubbo运行环境
一:简介 以前做项目时,分布式环境都是其它同事在搭建,自己也没参与分布式环境搭建,只负责开发,由于近段时间工作重心转到android,java后台有一段时间没有接触了,刚好这几天有空,决定自己动 ...
- leetcode算法:Distribute Candies
Given an integer array with even length, where different numbers in this array represent different k ...
- 未能加载文件或程序集“ RevitAPIUI.dll”
revit二次开发中遇到的问题 RevitAPIUI.dll 只能 Native Library 中执行: 脱离了Native Library,API是跑不起来的 . 检查程序流程:登录,配置,启动r ...
- Properties文件中文属性读取是乱码问题
项目当中遇到了需要从Properties文件中读取配置属性的需求,本来是存储的中文转码后的属性,但是考虑到后期更改问题就变成java代码中进行转码,代码如下: Properties pros = ne ...
- SpringBoot框架中JPA使用的一些问题
主要是自己在使用JPA框架时遇到的一个坑,拿出来分享一下 首先上一个简单JPA框架实体 public interface EnterpriseInfoDao extends JpaSpecificat ...
- Struts(十七):通过CURD来学习paramsPrepareParams拦截器栈
背景: 通过上一章节<Struts(十六):通过CURD来学习Struts流程及ModelDriven的用法>学习了ModelDriven拦截器的用法,上章节中讲到了edit功能. 要修改 ...
- java加密算法AES与RSA
1.commons-codec使用 commons-codes 常用工具类:DigestUtils,Base64,Hex 1.1 md5 String text = "hello,md5&q ...