transaction 包是 MyBatis 中负责进行事务管理的包,这个包中有两个子包,分别代表了两种不同的管理方式,jdbc 子包中包含基于 JDBC 进行事务管理的类,managed 子包中包含基于容器进行事务管理的类。
transaction 包结构
Transaction
是实现事务管理的顶层接口,可以通过其进行事务的管理。
TransactionFactory
是生成事务的顶层接口,可以通过其生成事务管理对象。
jdbc 子包
jdbc 子包代表的是 JDBC 事务,其中存放的也是 JdbcTransaction 类及其工厂类。是通过 JDBC 来实现事务的管理,代码实现如下:
public class JdbcTransaction implements Transaction {
// 连接
protected Connection connection;
// 数据源
protected DataSource dataSource;
// 事务隔离级别
protected TransactionIsolationLevel level;
// 是否为自动提交
protected boolean autoCommit;
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
dataSource = ds;
level = desiredLevel;
autoCommit = desiredAutoCommit;
}
public JdbcTransaction(Connection connection) {
this.connection = connection;
}
@Override
public Connection getConnection() throws SQLException {
// 如果没有连接,则开启一个新的连接
if (connection == null) {
openConnection();
}
return connection;
}
@Override
public void commit() throws SQLException {
// 连接存在并且连接是手动提交方式,则需要提交事务
if (connection != null && !connection.getAutoCommit()) {
connection.commit();
}
}
@Override
public void rollback() throws SQLException {
// 连接存在并且连接是手动提交方式,则进行回滚事务
if (connection != null && !connection.getAutoCommit()) {
connection.rollback();
}
}
@Override
public void close() throws SQLException {
if (connection != null) {
// 在关闭连接前设置 connection 提交方式为自动提交
// 可能有的小伙伴比较疑惑明明都要关闭连接了,还要修改连接的提交方式干嘛
// 其实这里是防止 close 被重写过,并不是真正的要关闭连接,而是要放回到连接池中
// 所以在回收连接前要重置连接的属性
resetAutoCommit();
// 关闭连接
connection.close();
}
}
// 设置连接的提交方式为期待的提交方式
// 如果提交方式不是期待的方式才进行设置,否则不做修改
protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
try {
if (connection.getAutoCommit() != desiredAutoCommit) {
connection.setAutoCommit(desiredAutoCommit);
}
} catch (SQLException e) {
throw new TransactionException();
}
}
// 重置自动提交
// 如果是手动提交就设置为自动提交
// 如果本身就是自动提交则不做修改
protected void resetAutoCommit() {
try {
if (!connection.getAutoCommit()) {
connection.setAutoCommit(true);
}
} catch (SQLException e) {
}
}
protected void openConnection() throws SQLException {
// 先通过数据源开启一个连接
connection = dataSource.getConnection();
// 这是事务隔离级别
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
// 设置是否开启自动提交
setDesiredAutoCommit(autoCommit);
}
@Override
public Integer getTimeout() throws SQLException {
return null;
}
}
JdbcTransactionFactory 是用来创建 JdbcTransaction,代码实现如下:
public class JdbcTransactionFactory implements TransactionFactory {
@Override
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
}
@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}
}
managed 子包
容器事务,是将事务操作都交给相应的容器进行管理,所以 MyBatis 自己并不需要做任何的操作。所以可以看到 commit、rollback 其实是空实现。
public class ManagedTransaction implements Transaction {
// 数据源
private DataSource dataSource;
// 事务隔离级别
private TransactionIsolationLevel level;
// 连接
private Connection connection;
// 是否可关闭连接,默认为 true
private final boolean closeConnection;
public ManagedTransaction(Connection connection, boolean closeConnection) {
this.connection = connection;
this.closeConnection = closeConnection;
}
public ManagedTransaction(DataSource ds, TransactionIsolationLevel level, boolean closeConnection) {
this.dataSource = ds;
this.level = level;
this.closeConnection = closeConnection;
}
@Override
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();
}
return this.connection;
}
@Override
public void commit() throws SQLException {
// 空实现
}
@Override
public void rollback() throws SQLException {
// 空实现
}
@Override
public void close() throws SQLException {
if (this.closeConnection && this.connection != null) {
this.connection.close();
}
}
protected void openConnection() throws SQLException {
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
}
@Override
public Integer getTimeout() throws SQLException {
return null;
}
}
同样的ManagedTransaction
也有其对应的工厂类 ManagedTransactionFactory
。代码实现如下:
public class ManagedTransactionFactory implements TransactionFactory {
// 是否可被关闭
private boolean closeConnection = true;
@Override
public void setProperties(Properties props) {
if (props != null) {
String closeConnectionProperty = props.getProperty("closeConnection");
if (closeConnectionProperty != null) {
closeConnection = Boolean.parseBoolean(closeConnectionProperty);
}
}
}
@Override
public Transaction newTransaction(Connection conn) {
return new ManagedTransaction(conn, closeConnection);
}
@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new ManagedTransaction(ds, level, closeConnection);
}
}
总结:这两种实现方案的代码都比较简单,因为本身的逻辑并不多,更多的都是在调用对应的类来进行事务的管理。这里也暂时不会讲解它们的使用场景,因为这个会留在后面一起学习。