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

问题:群里有人提出连接池在有事务和没事务的情况下(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、如果是嵌套事务,那么在开始本事务之前要保存前面的事务,在完成本事务后继续执行前面的事务。

你可能感兴趣的:(有事务和没事务的执行流程)