MyBatis的事务管理是由TransactionFactory
和Transaction
两个接口定义的,TransactionFactory
负责生成Transaction
,这是一个典型的工厂模式。
官方提供了事务管理的两种模式:
- Managed:对应
ManagedTransactionFactory
和ManagedTransaction
- JDBC:对应
JdbcTransactionFactory
和JdbcTransaction
重点看一下Transaction
中提交和回滚的实现:
public class ManagedTransaction implements Transaction {@Overridepublic void commit() throws SQLException {// Does nothing}@Overridepublic void rollback() throws SQLException {// Does nothing}}
public class JdbcTransaction implements Transaction {@Overridepublic void commit() throws SQLException {if (connection != null && !connection.getAutoCommit()) {if (log.isDebugEnabled()) {log.debug("Committing JDBC Connection [" + connection + "]");}connection.commit();}}@Overridepublic void rollback() throws SQLException {if (connection != null && !connection.getAutoCommit()) {if (log.isDebugEnabled()) {log.debug("Rolling back JDBC Connection [" + connection + "]");}connection.rollback();}}
}
可以看出,这两者的主要区别在于ManagedTransaction
不会进行实际的事务提交和回滚,而是交由外部进行控制,而JdbcTransaction
是我们能进行实际事务提交和回滚的,所以如果我们要手动控制事务,应该指定事务管理器为JdbcTransactionFactory
,例如在mybatis的配置文件中:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"></dataSource></environment></environments>
</configuration>
那Transaction
和实际执行查询的SqlSession
又是什么关系呢?原来是创建SqlSession
的时候会交由Executor
管理,一起传给SqlSession
:
public class DefaultSqlSessionFactory implements SqlSessionFactory {private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);final Executor executor = configuration.newExecutor(tx, execType);return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);} finally {ErrorContext.instance().reset();}}
}
当我们执行SqlSession
的commit()
时,实际上是调用Executor
的commit()
,进而调用Transaction
的commit()
:
public class DefaultSqlSession implements SqlSession {@Overridepublic void commit(boolean force) {try {executor.commit(isCommitOrRollbackRequired(force));dirty = false;} catch (Exception e) {throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e);} finally {ErrorContext.instance().reset();}}
}
public abstract class BaseExecutor implements Executor {@Overridepublic void commit(boolean required) throws SQLException {if (closed) {throw new ExecutorException("Cannot commit, transaction is already closed");}clearLocalCache();flushStatements();if (required) {transaction.commit();}}
}