当我们从数据源中得到一个可用的数据库连接之后,就可以开启一个数据库事务了,事务成功开启之后,我们才能修改数据库中的数据。
在修改完成之后,我们需要提交事务,完成整个事务内的全部修改操作,如果修改过程中出现异常,我们也可以回滚事务,放弃整个事务中的全部修改操作。
可见,控制事务在一个以数据库为基础的服务中,是一件非常重要的工作。
为此,MyBatis 专门抽象出来一个 Transaction
接口。
Transaction
接口是 MyBatis 中对数据库事务的抽象,其中定义了提交事务、回滚事务,以及获取事务底层数据库连接的方法。
Transaction
接口源码:
java
/**
* Wraps a database connection.
* Handles the connection lifecycle that comprises: its creation, preparation, commit/rollback and close.
*
* @author Clinton Begin
*/
public interface Transaction {
// 获取该事务关联的数据库连接对象
Connection getConnection() throws SQLException;
// 提交当前事务
void commit() throws SQLException;
// 回滚当前事务
void rollback() throws SQLException;
// 关闭当前事务关联的底层数据库连接
void close() throws SQLException;
// 获取当前事务超时时间
Integer getTimeout() throws SQLException;
}
JdbcTransaction、ManagedTransaction 是 MyBatis 自带的两个 Transaction 接口实现,这里也使用到了工厂方法模式,如下图所示:
TransactionFactory
是用于创建 Transaction
的工厂接口,其中最核心的方法是 newTransaction()
方法,它会根据数据库连接或数据源创建 Transaction
对象。
java
public interface TransactionFactory {
// 对TransactionFactory对象进行配置,一般紧跟在TransactionFactory对象初始化之后,
// 该方法主要是完成对TransactionFactory工厂的一些自定义配置
default void setProperties(Properties props) {
}
// 在指定的数据库连接之上创建一个Transaction对象
Transaction newTransaction(Connection conn);
// 从指定数据源中获取数据库连接,并在此数据库连接之上创建一个关联的Transaction对象
Transaction newTransaction(DataSource dataSource,
TransactionIsolationLevel level, boolean autoCommit);
}
JdbcTransactionFactory
和 ManagedTransactionFactory
是 TransactionFactory
的两个实现类,分别用来创建 JdbcTransaction
对象和 ManagedTransaction
对象,具体实现比较简单,这里就不再展示,你若感兴趣的话可以参考源码进行学习。
接下来,我们看一下 JdbcTransaction
的实现,其中维护了事务关联的数据库连接以及数据源对象,同时还记录了事务自身的属性,例如,事务隔离级别和是否自动提交。
在构造函数中,JdbcTransaction
并没有立即初始化数据库连接(也就是 connection
字段),connection
字段会被延迟初始化,具体的初始化时机是在调用 getConnection()
方法时,通过dataSource.getConnection()
方法完成初始化。
在日常使用数据库事务的时候,我们最常用的操作就是提交和回滚事务,Transaction
接口将这两个操作抽象为 commit()
方法和 rollback()
方法。在 commit()
方法和 rollback()
方法中,JdbcTransaction
都是通过 java.sql.Connection
的同名方法实现事务的提交和回滚的。
ManagedTransaction
的实现相较于 JdbcTransaction
来说,有些许类似,也是依赖关联的 DataSource
获取数据库连接,但其 commit()、rollback()
方法都是空实现,事务的提交和回滚都是依靠容器管理的,这也是它被称为 ManagedTransaction
的原因。
另外,与 JdbcTransaction
不同的是,ManagedTransaction
会根据初始化时传入的 closeConnection
值确定是否在事务关闭时,同时关闭关联的数据库连接(即调用其 close()
方法)。