1. 程式人生 > >Mybatis事務管理

Mybatis事務管理

一、Mybatis事務概述

      對於資料庫事務而言,一般包括以下幾個操作:建立、提交、回滾、關閉。MyBatis把這些抽象為Transaction介面:                        介面定義如下:

           

 介面定義了Connection連線、提交、回滾、關閉等功能。

Mybatis事務管理分為兩種方式:

     1、使用JDBC的事務管理機制:利用java.sql.Connection物件完成對事務的提交、回滾、關閉。

     2、使用MANAGED的事務管理機制:這種方式Mybatis自身不會去實現事務管理,而是交給容器(Tomcat、JBOSS)去管理。

二、Mybatis事務使用

1、 事務配置:  

      我們在用Mybatis時,一般會用如下配置檔案: 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <environments default="development">
    <environment id="development">
      <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>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

    其子節點<transactionManager> 的type 會決定我們用什麼型別的事務管理機制。              

2、事務工廠的建立: 

   Mybatis的事務是交給TransactionFactory來建立,如果我們將<transactionManager>的type 配置為"JDBC",那麼,在Mybatis初始化解析<environment>節點時,XMLConfigBuilder會根據type="JDBC"建立一個JdbcTransactionFactory工廠,其原始碼如下: 

private TransactionFactory transactionManagerElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      Properties props = context.getChildrenAsProperties();
      TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
      factory.setProperties(props);
      return factory;
    }
    throw new BuilderException("Environment declaration requires a TransactionFactory.");
  }

如果type = "JDBC",則Mybatis會建立一個JdbcTransactionFactory ;如果type="MANAGED",則Mybatis會建立一個MangedTransactionFactory。 

TransactionFactory介面:

建立Transaction有兩個方法:一是通過Connection物件建立,另一個是通過資料來源DataSource來建立。

看下JdbcTransactionFactory 建立過程,如下:

public class JdbcTransactionFactory implements TransactionFactory {
 
  public void setProperties(Properties props) {
  }
 
   //根據給定的資料庫連線Connection建立Transaction

  public Transaction newTransaction(Connection conn) {
    return new JdbcTransaction(conn);
  }
 
    // 根據DataSource、隔離級別和是否自動提交建立Transacion
 
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    return new JdbcTransaction(ds, level, autoCommit);
  }
}

3、事物管理的實現

我們以 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 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的commit()
    
  public void commit() throws SQLException {
    if (connection != null && !connection.getAutoCommit()) {
      if (log.isDebugEnabled()) {
        log.debug("Committing JDBC Connection [" + connection + "]");
      }
      connection.commit();
    }
  }
 
  //使用connection的rollback()
   
  public void rollback() throws SQLException {
    if (connection != null && !connection.getAutoCommit()) {
      if (log.isDebugEnabled()) {
        log.debug("Rolling back JDBC Connection [" + connection + "]");
      }
      connection.rollback();
    }
  }
 
    //使用connection的close()
  
  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) {
      throw new TransactionException("Error configuring AutoCommit.  "
          + "Your driver may not support getAutoCommit() or setAutoCommit(). "
          + "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);
    }
  }
 
  protected void resetAutoCommit() {
  //select操作沒有commit和rollback事務,一些資料庫在select操作是會開啟事務,一個變通方法是在關閉連線之前將autocommit設定為true。
    try {
      if (!connection.getAutoCommit()) {
        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);
  }
 
}