Mybatis+Springboot整体事务管理机制如下图
由图上可以清晰地看出来,Mybatis+Springboot的事务管理的核心类是SqlSessionFactoryBean,然后分为两大主线:Springboot事务管理一条主线,MyBatis自己管理事务一条主线;然后继续,Mybatis自己管理事务也分两条线:Jdbc管理事务一条线,Managed管理事务一条线。
- MyBatis使用Springboot的事务管理
在Springboot初始化SqlSessionFactoryBean的类里,有段如下代码
targetConfiguration.setEnvironment(new Environment(this.environment,
this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,
this.dataSource));
也就是说,如果Mybatis自己没有配置transactionFactory,那么就直接使用定义Springboot托管事务管理方案。所以,由此也可以得出一个结论,如果想使用Springboot托管Mybatis事务管理,就一定不能配置Mybatis自己的事务管理。
我们再来看SpringManagedTransactionFactory
它直接使用的是SpringManagedTransaction事务,其核心代码如下
有此可见,其使用DataSourceUtils去获取Springboot的事务管理配置来管理Mybatis事务配置。
这就是Springboot托管Mybatis的事务的核心业务逻辑。
下面,我们来看看Springboot是如何把自己的事务管理传递给Mybatis的。
在我们使用的DataSourceTransactionManager中,有一段如下代码
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
其中,我们看到了
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
这里大家可以看下TransactionSynchronizationManager的源代码,它借助ThreadLocal把事务定义存储到缓存中。
我们回头来看看Mybatis的Springboot事务管理类SpringManagedTransaction的openConnection()方法有下面代码
this.connection = DataSourceUtils.getConnection(this.dataSource);
接着往下看
private static Connection fetchConnection(DataSource dataSource) throws SQLException {
Connection con = dataSource.getConnection();
if (con == null) {
throw new IllegalStateException("DataSource returned null from getConnection(): " + dataSource);
}
return con;
}
这里,如果能从TransactionSynchronizationManager缓存获取到connection那么就直接拿来用,如果获取不到就直接取数据库管理事务的链接。
而由前面的分析可知,在Springboot托管事务情况下,TransactionSynchronizationManager缓存中是有定义好事务管理信息的connection的,此时就是用Springboot的事务定义来管理Mybatis的事务,实现了事务托管。
- Mybatis使用自己的事务管理
在这种情况下,Springboot未启用事务管理,或者Mabatis配置了自己的事务管理,也就是this.transactionFactory不为空,而此时我们只需要在配置文件中定义TransactionFactory为JdbcTransactionFactory或者ManagedTransactionFactory,然后注入到SqlSessionFactoryBean中,即可实现Mybatis使用自己的事务管理机制。
--End--