MyBatis的事务管理是由TransactionFactory
和Transaction
两个接口定义的,TransactionFactory
负责生成Transaction
,这是一个典型的工厂模式。
官方提供了事务管理的两种模式:
- Managed:对应
ManagedTransactionFactory
和ManagedTransaction
- JDBC:对应
JdbcTransactionFactory
和JdbcTransaction
重点看一下Transaction
中提交和回滚的实现:
java
public class ManagedTransaction implements Transaction {
@Override
public void commit() throws SQLException {
// Does nothing
}
@Override
public void rollback() throws SQLException {
// Does nothing
}
}
java
public class JdbcTransaction implements Transaction {
@Override
public void commit() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Committing JDBC Connection [" + connection + "]");
}
connection.commit();
}
}
@Override
public 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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//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
:
java
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()
:
java
public class DefaultSqlSession implements SqlSession {
@Override
public 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();
}
}
}
java
public abstract class BaseExecutor implements Executor {
@Override
public void commit(boolean required) throws SQLException {
if (closed) {
throw new ExecutorException("Cannot commit, transaction is already closed");
}
clearLocalCache();
flushStatements();
if (required) {
transaction.commit();
}
}
}