mybatis事务管理机制详解

Posted 51life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis事务管理机制详解相关的知识,希望对你有一定的参考价值。

1.mybatis事务的配置和使用

mybatis事务有两种使用方式:

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

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

在配置文件中的配置:

    <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()); } } }











以上是关于mybatis事务管理机制详解的主要内容,如果未能解决你的问题,请参考以下文章

mybatis配置文件详解

14.VisualVM使用详解15.VisualVM堆查看器使用的内存不足19.class文件--文件结构--魔数20.文件结构--常量池21.文件结构访问标志(2个字节)22.类加载机制概(代码片段

《深入理解mybatis原理2》 Mybatis初始化机制详解

mybatis深入理解-----Mybatis初始化机制详解

Mybatis的缓存机制详解

《深入理解mybatis原理》 Mybatis初始化机制详解