我们在使用Mybatis时会配置SqlSessionFactoryBean用于创建SqlSessionFactory,在buildSqlSessionFactory()方法中我们就可以看到TransactionFactory的创建,TransactionFactory就是事务管理的基础。TransactionFactory也是可以在配置中配置的,如果没配置就使用SpringManagedTransactionFactory,SpringManagedTransactionFactory功能就创建SpringManagedTransaction事务管理对象来管理Mybatis中的数据库事务。
1、SqlSessionFactoryBean.buildSqlSessionFactory()
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
//Mybatis全局配置
Configuration configuration;
.................
if (this.transactionFactory == null) {
// 默认使用SpringManagedTransactionFactory
this.transactionFactory = new SpringManagedTransactionFactory();
}
// 把transactionFactory保存在Configuration中,便于其它地方获取使用
Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);
configuration.setEnvironment(environment);
.................
//根据全局配置创建SqlSessionFactory
return this.sqlSessionFactoryBuilder.build(configuration);
}
2、SpringManagedTransaction.openConnection()
//在获取数据库连接时调用的方法
private void openConnection() throws SQLException {
//通过spring的DataSourceUtils工具类获取数据连接
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();
this.isConnectionTransactional = isConnectionTransactional(this.connection, this.dataSource);
................
}
3、DataSourceUtils.doGetConnection()
//最终获取数据库连接的方法
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//spring事务管理一个核心类TransactionSynchronizationManager,TransactionSynchronizationManager里面通过ThreadLocal变量保存了dataSource对应的ConnectionHolder,实现了spring的事务传播特性。
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = dataSource.getConnection();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering transaction synchronization for JDBC Connection");
// Use same Connection for further JDBC actions within the transaction.
// Thread-bound object will get removed by synchronization at transaction completion.
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
else {
holderToUse.setConnection(con);
}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
}
return con;
}