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();}}
}