有事务和没事务的执行流程

问题:群里有人提出连接池在有事务和没事务的情况下(spring+mybatis),一个service中调用了几个mapper,那么每个mapper用的连接是同一个吗?
分析:经测试在有事务的情况下用的连接是同一个,无事务的情况下用的连接不是同一个。一般对于CUD操作来说都要设置REQUIRED事务,R操作也要设置事务SUPPORT+readonly。不推荐无事务的方法。

mybatis执行流程(无spring事务集成):
1、MapperProxy.invoke()
2、SqlSessionTemplate$SqlSessionInterceptor.invoke()
3、new一个DefaultSqlSession
4、取connection
5、从Configuration中得到MappedStatement,设置pstmt参数,执行sql语句。【MappedStatement是在xxxMapper实例化的时候去mapper.xml中解析的】
6、得到resultSet,解析rs。
7、关闭sqlSession,还connection。

没有spring事务的情况下:
1、xxxMapper是一个代理,真正执行逻辑的是MapperProxy.invoke()->MapperMethod.execute()->SqlSessionTemplate.CRUD()
2、在sqlSessionTemplate中用到了SqlSession,也是一个代理,执行逻辑的是SqlSessionInterceptor.invoke(),
3、在SqlSessionInterceptor.invoke()中去获取SqlSession,首先是从TransactionSynchronizationManager.resources中获取,为null去new一个DefaultSqlSession(同时创建一个新的SpringManagedTransaction),然后判断如果有spring事务就会把sqlSession绑定到TransactionSynchronizationManager.resources,并添加SqlSessionSynchronization【这里没有spring事务,所以不会绑定和添加】,
4、然后判断TransactionSynchronizationManager.isSynchronizationActive()是否当前线程开启了事务同步,这里返回false,在SimpleExecutor中去获取数据库连接(这时出发连接池初始化(druid)),
5、得到的connection对象的autocommit=true(如果有事务,在事务的doBegin方法中会把autocommit=false),SqlSessionInterceptor.invoke()中判断是否sqlSession有事务,如果没有则执行sqlSession.commit(),在这里执行SpringManangedTransaction.commit()【注:这里虽然叫SpringManagedTransaction,但是它和spring事务没有任何关系,同时由于autocommit=true,因此也不会提交事务】,然后执行sqlSession.close(),把connection还给druid。
多个xxxMapper就重复上面的步骤。新的connection,新的sqlSession,新的SpringManagedTransaction。

在有spring事务的情况执行流程:
1、xxxService会被cglib重写,执行DynamicAdvisedInterceptor.intercept(), 执行TransactionInterceptor.invode()->invokeWithinTransaction(),
2、在DataSourceTransactionManager.doBegin()中取得Connection连接,取消自动提交,设置隔离级别和事务超时时间,绑定当前connection到threadLocal,
3、然后转回xxxService中执行xxxMapper方法。
xxxMapper是代理,执行进入MapperProxy,进入MapperMethod,进入SqlSessionTemplate,sqlSessionTemplate中,sqlSessionProxy又是SqlSessionInterceptor代理,在SqlSessionInterceptor的invoke()中,得到DefaultSqlSession,把它绑定到TransactionSynchronizationManager.resources,【DefaultSqlSession绑定到线程是关键,所有操作都用的是同一个sqlSession(connection),这样抱着了事务】
4、mybatis执行完毕
5、spring提交事务,在DataSourceTransactionManager.triggerBeforeCommit()中调用SqlSessionSynchronization.beforeCommit()去做一些清除缓存工作(并不提交事务),从TransactionSynchronizationManager.resources中释放sqlSession。
6、提交事务
7、通知SqlSessionSynchronization.afterCommit()
8、从线程ThreadLocal中释放dataSource
9、复原connection原先的autocommit=true和隔离级别
10、还connection到连接池
11、如果是嵌套事务,那么在开始本事务之前要保存前面的事务,在完成本事务后继续执行前面的事务。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,080评论 19 139
  • 前面的章节主要讲mybatis如何解析配置文件,这些都是一次性的初始化过程。从本章开始讲解动态的过程,它们跟应用程...
    七寸知架构阅读 4,979评论 2 55
  • # 前言 在java程序员的世界里,最熟悉的开源软件除了 Spring,Tomcat,还有谁呢?当然是 Mybat...
    莫那一鲁道阅读 3,343评论 3 11
  • 单独使用mybatis是有很多限制的(比如无法实现跨越多个session的事务),而且很多业务系统本来就是使用sp...
    七寸知架构阅读 3,504评论 0 53
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,987评论 6 342