首页 > 编程语言 >【Mybatis】【事务管理器】【一】Mybatis源码解析-事务管理器

【Mybatis】【事务管理器】【一】Mybatis源码解析-事务管理器

时间:2023-03-02 21:47:58浏览次数:34  
标签:事务 管理器 Connection Override connection closeConnection Mybatis public

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

标签:事务,管理器,Connection,Override,connection,closeConnection,Mybatis,public
From: https://www.cnblogs.com/kukuxjx/p/17170540.html

相关文章

  • 如何查看任务管理器中某个进程的详细命令行
    有一次追查一个进程,然后想起来任务管理器可以查看进程命令行,做下记录并提供给有需要的同学首先右键,选择"任务管理器"打开任务管理器   发现没有显示命令行那一列信......
  • mybatis 实现 if..else
    mybatis中可以通过使用下列标签,配合if标签实现java中if...else...的效果,减少查库的次数<choose><when></when><otherwise></otherwise></choose>下面是实例展......
  • MySQL进阶—事务
    事务事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,所以这些操作要么同时成功,要么同时失败。事务的四大特性......
  • Java应用【Ⅺ】在 Java 中使用MyBatis框架进行关系型数据库操作
    如果您觉得本博客的内容对您有所帮助或启发,请关注我的博客,以便第一时间获取最新技术文章和教程。同时,也欢迎您在评论区留言,分享想法和建议。谢谢支持!相关阅读:​​Java应用【......
  • 存储过程块与事务控制
    KingbaseES的存储过程内的事务默认与外部调用者的事务是合并在一起的:存储过程内部的提交或回退会影响外部事务,而外部事务的提交或回退也会影响存储过程内部的事务。可以通......
  • SpringBoot+MybatisPlus+MySql 自动生成代码 自动分页
    SpringBoot+MybatisPlus+MySql自动生成代码自动分页一、配置<!--Mybatisplus--><dependency><groupId>com.baomidou</groupId>......
  • Mybatis-Plus学习
    mybatis-plus学习系统环境jdk8+mysql5.7+springBoot+mybatis最新版本+系统编码UTF-8文件配置application.properties#应用名称spring.application.name=mybatisplu......
  • MyBatis基础
    概念      快速入门创建user表,添加数据CREATEDATABASEmybatis;USEmybatis;DROPTABLEIFEXISTStb_user;CREATETABLEtb_user(idINTPRIM......
  • 九、MybatisPlus的多数据源
    场景适用于多种场景:纯粹多库、读写分离、一主多从、混合模式等目前我们就来模拟一个纯粹多库的一个场景,其他场景类似场景说明:我们创建两个库,分别为:mybatis_plus(以前......
  • 八、MybatisPlus的代码生成器示例
    引入依赖<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version></dependency><dependency> <......