【Mybatis】【事务管理器】【一】Mybatis源码解析-事务管理器
1 前言
在了解数据源后,我们来看下事务管理器,这个东西也很重要。
2 事务管理器类型
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚功能,它依赖从数据源获得的连接来管理事务作用域。默认情况下,为了与某些驱动程序兼容,它在关闭连接时启用自动提交。然而,对于某些驱动程序来说,启用自动提交不仅是不必要的,而且是一个代价高昂的操作。因此,从 3.5.10 版本开始,你可以通过将 "skipSetAutoCommitOnClose" 属性设置为 "true" 来跳过这个步骤。例如:
<transactionManager type="JDBC"> <property name="skipSetAutoCommitOnClose" value="true"/> </transactionManager>
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
简单的来说就是 JDBC 类型的会帮我们自动提交事务,MANAGED 类型的事务提交回滚自主管理。
3 源码分析
3.1 切入时机
我们先来回顾下我们的事务管理器是什么时候入场的,我们的事务管理器是配置在环境变量里的,所以我们事务的创建也就是在解析环境变量的时候,我们回顾下:
private void environmentsElement(XNode context) throws Exception { if (context != null) { ... } for (XNode child : context.getChildren()) { ... if (isSpecifiedEnvironment(id)) { // 解析 transactionManager 节点 TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); // 解析 dataSource 节点 DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); // 创建 DataSource 对象 DataSource dataSource = dsFactory.getDataSource(); Environment.Builder environmentBuilder = new Environment.Builder(id) .transactionFactory(txFactory) .dataSource(dataSource); // 构建 Environment 对象,并设置到 configuration 中 configuration.setEnvironment(environmentBuilder.build()); } } } }
private TransactionFactory transactionManagerElement(XNode context) throws Exception { if (context != null) { // 获取事务管理器的类型值 String type = context.getStringAttribute("type"); // 获取属性 Properties props = context.getChildrenAsProperties(); // 根据类型创建对应的事务工厂对象完事 TransactionFactory factory = (TransactionFactory) resolveClass(type).getDeclaredConstructor().newInstance(); factory.setProperties(props); return factory; } throw new BuilderException("Environment declaration requires a TransactionFactory."); }
那么我们具体看下两种类型的事务工厂吧。
3.2 事务工厂
我们先来看下类图,其实跟我们的数据源基本设计上是一致的,都是一个顶层接口定义两个方法,下边挂多个实现类。
我们简单来看下两个事务工厂类的实现:
3.2.1 JdbcTransactionFactory
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); } }
3.2.2 JdbcTransactionFactory
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); } }
两个事务工厂内容基本都一致,都是创建对应的事务对象完事。那么我们再看一下两个事务对象。
3.3 Transaction
一样我们先来看下类图关系,都是我们常见事务方法:提交、回滚、关闭、隔离级别,那么我们具体的看一下每种事务对象的内容。
3.3.1 Transaction - JdbcTransaction
public class JdbcTransaction implements Transaction { private static final Log log = LogFactory.getLog(JdbcTransaction.class); // 数据库连接 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()) { 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(); } } @Override // 关闭事务 public void close() throws SQLException { if (connection != null) { // 重置自动提交标志 resetAutoCommit(); if (log.isDebugEnabled()) { log.debug("Closing JDBC Connection [" + connection + "]"); } // 连接关闭 connection.close(); } }protected void openConnection() throws SQLException { if (log.isDebugEnabled()) { log.debug("Opening JDBC Connection"); } connection = dataSource.getConnection(); if (level != null) { connection.setTransactionIsolation(level.getLevel()); } setDesiredAutoCommit(autoCommit); } }
3.3.2 Transaction - ManagedTransaction
public class ManagedTransaction implements Transaction { private static final Log log = LogFactory.getLog(ManagedTransaction.class); private DataSource dataSource; private TransactionIsolationLevel level; private Connection connection; 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 { // Does nothing } @Override public void rollback() throws SQLException { // Does nothing } @Override public void close() throws SQLException { if (this.closeConnection && this.connection != null) { if (log.isDebugEnabled()) { log.debug("Closing JDBC Connection [" + this.connection + "]"); } this.connection.close(); } } }
内容比较简单,这里就不做过多介绍哈,我们可以看到 JDBC 类型的事务会帮我们自动提交或者回滚,而 Managed 类型的事务其实什么也没做,需要我们自己控制事务。
4 小结
关于事务的内容我们就了解到这里,其实 Spring 里边也有一个事务对象就是 SpringManagedTransaction,我们后续在讲整合的时候再讨论哈,有理解不对的地方欢迎指正哈。