• mybatis事务管理机制详解


    1.mybatis事务的配置和使用

    mybatis事务有两种使用方式:

    (a):使用JDBC的事务管理机制:即使用java.Sql.Connection对象完成对事务的提交,回滚和关闭操作。

    (b):使用MANAGED的事务管理机制:mybatis本身不会去实现事务管理的相关操作,而是交个外部容器来管理事务。当与spring整合使用后,一般使用spring来管理事务。

    在配置文件中的配置:

        <environments default="development">
            <environment id="development">
    //JDBC的事务方式 <transactionManager type="JDBC" />
    <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments>

    在这段配置信息中,有三个节点:<transactionManager />,<dataSource>,<environment>。其中,<dataSource>节点封装了数据源的信息,<environment>封装了数据库的连接,包括数据源和事务,然后把该节点信息封装到了Configuration对象中,方便后面使用,现在看下mybatis在初始化加载配置文件时,对<environment/>节点的解析:

      private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
          if (environment == null) {
            environment = context.getStringAttribute("default");
          }
          for (XNode child : context.getChildren()) {
            String id = child.getStringAttribute("id");
            if (isSpecifiedEnvironment(id)) {
    // 解析 <transactionManager>节点,获取事务工厂对象 进入该方法 TransactionFactory txFactory
    = transactionManagerElement(child.evalNode("transactionManager"));
    // 解析<DataSource>节点,获取数据源对象 DataSourceFactory dsFactory
    = dataSourceElement(child.evalNode("dataSource")); DataSource dataSource = dsFactory.getDataSource(); Environment.Builder environmentBuilder = new Environment.Builder(id) .transactionFactory(txFactory) .dataSource(dataSource); configuration.setEnvironment(environmentBuilder.build()); } } } }

     进入解析<transactionManager/>节点的方法:

      private TransactionFactory transactionManagerElement(XNode context) throws Exception {
        if (context != null) {
    // 获取type的属性值,JDBC或者MANAGED String type
    = context.getStringAttribute("type"); Properties props = context.getChildrenAsProperties();
    //生成一个TransactionFactory实例 TransactionFactory factory
    = (TransactionFactory) resolveClass(type).newInstance(); factory.setProperties(props); return factory; } throw new BuilderException("Environment declaration requires a TransactionFactory."); }

    2.事务工厂TransactionFactory

    TransactionFactory定义了创建Transaction的两种方法,如下:

    public interface TransactionFactory {
    
      /**
       * Sets transaction factory custom properties.
       * @param props
       */
      void setProperties(Properties props);
    
      /**
       * Creates a {@link Transaction} out of an existing connection.
       * @param conn Existing database connection
       * @return Transaction
       * @since 3.1.0
    * 方法一:通过指定的Connection对象来创建事务
    */ Transaction newTransaction(Connection conn); /** * Creates a {@link Transaction} out of a datasource. * @param dataSource DataSource to take the connection from * @param level Desired isolation level * @param autoCommit Desired autocommit * @return Transaction * @since 3.1.0
    * 方法二:通过DataSource,隔离级别,是否自动提交 来创建事务
    */ Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit); }

    TransactionFactory有两个子类:JdbcTransactionFactory和ManagedTransactionFactory

    2.1 JdbcTransactionFactory,会创建JDBC类型的事务,就是JdbcTransaction,看下源码:

    public class JdbcTransactionFactory implements TransactionFactory {
    
      public void setProperties(Properties props) {
      }
      // JDBCTransaction的创建有两种方法  
      public Transaction newTransaction(Connection conn) {
        return new JdbcTransaction(conn);
      }
    
      public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
        return new JdbcTransaction(ds, level, autoCommit);
      }
    }

    2.2 ManagedTransactionFactory,会创建MANAGED类型的事务,ManagedTransaction,同样有两种方法:

    public class ManagedTransactionFactory implements TransactionFactory {
    
      private boolean closeConnection = true;
    
      public void setProperties(Properties props) {
        if (props != null) {
          String closeConnectionProperty = props.getProperty("closeConnection");
          if (closeConnectionProperty != null) {
            closeConnection = Boolean.valueOf(closeConnectionProperty);
          }
        }
      }
    
      public Transaction newTransaction(Connection conn) {
        return new ManagedTransaction(conn, closeConnection);
      }
    
      public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
        // Silently ignores autocommit and isolation level, as managed transactions are entirely
        // controlled by an external manager.  It's silently ignored so that
        // code remains portable between managed and unmanaged configurations.
        return new ManagedTransaction(ds, level, closeConnection);
      }
    }

    3.JdbcTransaction和ManagedTransaction

     3.1 JdbcTransaction

    从源码可知:jdbcTransaction从DataSource获取连接对象Connection,然后利用Connection对象管理事务的commit和rollback,实际在事务处理上,jdbcTransaction是对java.sql.Connection的一个包装,它是使用Connection对象来管理事务的。

    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 autoCommmit; //是否自动提交
    
      public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
        dataSource = ds;
        level = desiredLevel;
        autoCommmit = desiredAutoCommit;
      }
    
      public JdbcTransaction(Connection connection) {
        this.connection = connection;
      }
    
    // 获取连接对象
    public Connection getConnection() throws SQLException { if (connection == null) { openConnection(); } return connection; } // 使用Connection对象提交 public void commit() throws SQLException { if (connection != null && !connection.getAutoCommit()) { if (log.isDebugEnabled()) { log.debug("Committing JDBC Connection [" + connection + "]"); } connection.commit(); } } public void rollback() throws SQLException { if (connection != null && !connection.getAutoCommit()) { if (log.isDebugEnabled()) { log.debug("Rolling back JDBC Connection [" + connection + "]"); } connection.rollback(); } } public void close() throws SQLException { if (connection != null) { resetAutoCommit(); if (log.isDebugEnabled()) { log.debug("Closing JDBC Connection [" + connection + "]"); } connection.close(); } } protected void setDesiredAutoCommit(boolean desiredAutoCommit) { try { if (connection.getAutoCommit() != desiredAutoCommit) { if (log.isDebugEnabled()) { log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]"); } connection.setAutoCommit(desiredAutoCommit); } } catch (SQLException e) { // Only a very poorly implemented driver would fail here, // and there's not much we can do about that. throw new TransactionException("Error configuring AutoCommit. " + "Your driver may not support getAutoCommit() or setAutoCommit(). " + "Requested setting: " + desiredAutoCommit + ". Cause: " + e, e); } } protected void resetAutoCommit() { try { if (!connection.getAutoCommit()) { // MyBatis does not call commit/rollback on a connection if just selects were performed. // Some databases start transactions with select statements // and they mandate a commit/rollback before closing the connection. // A workaround is setting the autocommit to true before closing the connection. // Sybase throws an exception here. if (log.isDebugEnabled()) { log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]"); } connection.setAutoCommit(true); } } catch (SQLException e) { log.debug("Error resetting autocommit to true " + "before closing the connection. Cause: " + e); } } protected void openConnection() throws SQLException { if (log.isDebugEnabled()) { log.debug("Opening JDBC Connection"); }
    // 从数据源获取连接对象 connection
    = dataSource.getConnection(); if (level != null) { connection.setTransactionIsolation(level.getLevel()); } setDesiredAutoCommit(autoCommmit); } }

    3.2 ManagedTransaction 

    ManagedTransaction对事务的commit和rollback交给了容器去管理,自己本身并没有做任何处理,看源码:

    public class ManagedTransaction implements Transaction {
    
      private static final Log log = LogFactory.getLog(ManagedTransaction.class);
    
      private DataSource dataSource;
      private TransactionIsolationLevel level;
      private Connection connection;
      private boolean closeConnection;
    public Connection getConnection() throws SQLException {
        if (this.connection == null) {
          openConnection();
        }
        return this.connection;
      }
       
    // 没有做任何处理,因为交给了外部容器去做这件事了
    public void commit() throws SQLException { // Does nothing } public void rollback() throws SQLException { // Does nothing } public void close() throws SQLException { if (this.closeConnection && this.connection != null) { if (log.isDebugEnabled()) { log.debug("Closing JDBC Connection [" + this.connection + "]"); } this.connection.close(); } } protected void openConnection() throws SQLException { if (log.isDebugEnabled()) { log.debug("Opening JDBC Connection"); } this.connection = this.dataSource.getConnection(); if (this.level != null) { this.connection.setTransactionIsolation(this.level.getLevel()); } } }
  • 相关阅读:
    npm install遇到的问题
    已经安装了node和npm,输入node -v 未找到命令
    虚拟机VMware搭建代码环境
    使用VMware出现的各种问题
    bind、delegate、on的区别
    软件设计原则
    Qt 模型/视图/委托
    UML类图与类间六种关系表示
    C++内存分配与释放
    SQLite 自定义函数,聚合,排序规则
  • 原文地址:https://www.cnblogs.com/51life/p/9553762.html
Copyright © 2020-2023  润新知