【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,我们后续在讲整合的时候再讨论哈,有理解不对的地方欢迎指正哈。

posted @ 2023-03-02 21:34  酷酷-  阅读(240)  评论(0编辑  收藏  举报