关于java:Mybatis事务管理机制

6次阅读

共计 4208 个字符,预计需要花费 11 分钟才能阅读完成。

无关数据库事务的基础知识请翻看后面 Spring 事务管理的几篇文章,与 Spring 事务管理相比,Mybatis 的事务管理
非常简单。

底层构造

先相熟一下 Mabtis 事务相干的几个概念、或者说他的底层构造。

TransactionFactory:事务工厂,Mybatis 执行数据库操作、获取 SqlSession 之前要通过 TransactionFactory 来获取事务管理器。

Transaction:事务管理器,Mybatis 最终通过 Transaction 来实现对数据库操作的事务管制。

TransactionFactory 的配置

从 TransactionFactory 的类图能够看到 Mybatis 共提供了 3 种不同的事务工厂:

  1. JDBCTransactionFactory: 基于 JDBC 的事务工厂,负责创立 JDBCTransaction。
  2. ManagedTransactionFactory:“被治理的事务工厂”,负责创立 ManagedTransaction。
  3. SpringManagedTransactionFactory:Spring 治理的事务工厂,负责创立 SpringManagedTransaction。

能够通过 Mybatis 的环境配置 Environment 来指定具体应用哪一种事务管理工厂:

 <environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <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 属性能够指定 type=“JDBC”或者“MANAGED”,调配对应上述的 JDBCTransactionFactory 和 ManagedTransactionFactory。

然而,如果你正在应用 Spring + Mybatis,则 SpringManagedTransactionFactory 会笼罩掉以上两种设置。

Transaction

Mybatis 的事务管制行为最终由 Transaction 实现,Transaction 的接口定义非常简单:

public interface Transaction {Connection getConnection() throws SQLException;
  void commit() throws SQLException;
  void rollback() throws SQLException;
  void close() throws SQLException;
  Integer getTimeout() throws SQLException;}

getConnection 负责获取数据库连贯,commit 提交事务,rollback 回滚事务,close 敞开数据库连贯,getTimeout 获取事务超时工夫设置。

Mybatis 的三种不同的事务管理器须要实现 Transaction 接口的以上办法从而实现事务管制。

JDBCTransaction

如果咱们的我的项目配置了 Mybatis 的事务管理器为 JDBC 的话,Mybatis 会应用 JDBCTransaction 来最终实现事务管制,其实也就是上述 Transaction 接口的几个办法的实现。

JDBCTransactoin 源码非常简单,高深莫测。如果事务曾经开启的话(数据库连贯 autoCommit=false)则 commit 和 rollback 都是间接调用数据库连贯的 commit 和 rollback 办法实现事务的提交或回滚。

close 办法略微有一点点非凡,就是在敞开数据库连贯之前还调用了一个 resetAutoCommit()办法,将数据库连贯的 autoCommit 设置为 true(默认值)。其实这个动作是为了兼容连接池的配置,如果是池化治理数据库连贯的话,close 办法的其实是将 connection 交给连接池而并非真正的敞开,在偿还连接池之前复原其默认值应该也属于“最佳实际”的一种。

  @Override
  public void close() throws SQLException {if (connection != null) {resetAutoCommit();
      if (log.isDebugEnabled()) {log.debug("Closing JDBC Connection [" + connection + "]");
      }
      connection.close();}
  }

JDBCTransactoin 其实属于手动管制事务的一种,目前利用应该非常少了。因为他相当于是在获取 SqlSession 的同时获取数据库连贯并开启了事务,而咱们利用中一个交易往往须要屡次执行数据库操作,也就会屡次获取 SqlSession,因而也就不太容易通过 JDBCTransactoin 管制事务。

个别状况下咱们的我的项目还是要交给第三方事务管理器来实现事务管制,比方 Spring 的事务管理机制。

ManagedTransaction

MangedTransaction 的实现就更简略了,因为他把事务管制交给了不出名的第三方,所以他齐全不论了。

除了获取和敞开链接外,事务的提交和回滚都是空架子,啥也不干:

  @Override
  public void commit() throws SQLException {// Does nothing}

SpringManagedTransaction

如果应用 Spring+Mybatis 的话,Mybatis 应用 SpringManagedTransaction 进行事务管制。

getConnection 办法要借助 DataSourceUtil 的 getConnection,咱们看一下 DataSourceUtil 曾经是在 org.springframework.jdbc.datasource 包下,阐明控制权曾经交给 Spring 了:

public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
        try {return doGetConnection(dataSource);
        }
        catch (SQLException ex) {throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);
        }
        catch (IllegalStateException ex) {throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection:" + ex.getMessage());
        }
    }

调用了 doGetConnection 办法,其中呈现了咱们相熟的 TransactionSynchronizationManager 和 ConnectionHolder:

public static Connection doGetConnection(DataSource dataSource) throws SQLException {Assert.notNull(dataSource, "No DataSource specified");

        ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
        if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {conHolder.requested();
            if (!conHolder.hasConnection()) {logger.debug("Fetching resumed JDBC Connection from DataSource");
                conHolder.setConnection(fetchConnection(dataSource));
            }
            return conHolder.getConnection();}

具体能够参考后面无关 Spring 事务管制的相干文章。

commit 和 rollback 的代码更简略:

  @Override
  public void commit() throws SQLException {if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {LOGGER.debug(() -> "Committing JDBC Connection [" + this.connection + "]");
      this.connection.commit();}
  }

工作原理是:以后 connection 与从 Spring 的 ConnectionHolder 中获取到的 connection 是否是同一对象(this.isConnectionTransactional==true),是的话则啥也不干(交给 Spring 的事务管理去干),不是的话就与 JDBCTransaction 一样、本人提交事务。

总结

Mybatis 能够本人处理事务,也能够撒手不管、交给其余事务处理框架去解决。

Mybatis 并非事务处理专家,绝大多数状况下 Mybatis 都是撒手不管的,把事务交给 Spring 等更加善于事务管理的框架去解决。

Spring 事务管理相干内容请参考:https://segmentfault.com/a/11…

上一篇 Mybatis 缓存机制

正文完
 0