疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

MyBatis的事务管理之事务配置


 

 
11.1.3 事务的配置创建和使用
 
1. 事务的配置
我们在使用MyBatis时,一般会在MyBatis的根配置文件mybatis-config.xml中定义类似如下的信息:
 
<environment id="mysql">
    <!--  指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 
         type="MANAGED"指让容器实现对事务的管理
    -->
     <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>
复制代码
 
<environment >元素定义了连接某个数据库的信息,其子元素< transactionManager > 的type 决定我们用什么类型的事务管理机制。
 
 
2. 事务工厂的创建
MyBatis事务的创建是交给org.apache.ibatis.transaction.TransactionFactory 事务工厂来完成的。如果我们将<transactionManager>的type配置为JDBC,那么,在MyBatis初始化解析<environment>节点时,会根据type="JDBC"创建一个JdbcTransactionFactory工厂,其源码如下:
 
// 解析<transactionManager>节点,创建对应的TransactionFactory
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
/*
    在Configuration初始化的时候,会通过以下语句,注册JDBC和MANAGED对应的工厂类
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
   */
      if (context != null) {
          String type = context.getStringAttribute("type");
          Properties props = context.getChildrenAsProperties();
          // 创建对应的工厂实例,返回的是JdbcTransactionFactory或者
MangedTransactionFactory其中之一
           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的实例。
 
 
3. 事务工厂TransactionFactory
通过事务工厂TransactionFactory很容易获取到Transaction对象实例。我们以JdbcTransaction为例,看一下JdbcTransactionFactory是怎样生成JdbcTransaction的。JdbcTransaction源代码如下:
 
public class JdbcTransactionFactory implements TransactionFactory {
  @Override
  public void setProperties(Properties props) {
  }
  // 根据给定的数据库连接Connection创建Transaction
  @Override
  public Transaction newTransaction(Connection conn) {
    return new JdbcTransaction(conn);
  }
  // 根据DataSource、隔离级别和是否自动提交创建Transacion
  @Override
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    return new JdbcTransaction(ds, level, autoCommit);
  }
}
复制代码
 
如上代码所示,JdbcTransactionFactory会创建JDBC类型的Transaction,即JdbcTransaction。类似地,ManagedTransactionFactory也会创建ManagedTransaction。下面我们分别深入解析JdbcTranaction 和ManagedTransaction,看它们到底是怎样实现事务管理的。
 
 
4. JdbcTranaction
JdbcTransaction可直接使用JDBC的提交和回滚事务管理机制。它依赖于从dataSource中取得的连接connection来管理transaction的作用域,connection对象的获取被延迟到调用getConnection()方法时。如果autocommit设置为on,开启状态的话,则它会忽略commit和rollback。
也就是说,JdbcTransaction是使用java.sql.Connection 上的commit和rollback功能来完成事务操作的,JdbcTransaction只是相当于对java.sql.Connection事务处理进行了再次封装,Transaction的事务管理都是通过java.sql.Connection实现的。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;
  }
  @Override
  public Connection getConnection() throws SQLException {
    if (connection == null) {
      openConnection();
    }
    return connection;
  }
  // 使用connection的commit()
  @Override
  public void commit() throws SQLException {
    if (connection != null && !connection.getAutoCommit()) {
      if (log.isDebugEnabled()) {
        log.debug("Committing JDBC Connection [" + connection + "]");
      }
      connection.commit();
    }
  }
  // 使用connection的rollback()
  @Override
  public void rollback() throws SQLException {
    if (connection != null && !connection.getAutoCommit()) {
      if (log.isDebugEnabled()) {
        log.debug("Rolling back JDBC Connection [" + connection + "]");
      }
      connection.rollback();
    }
  }
  // 使用connection的close()
  @Override
  public void close() throws SQLException {
    if (connection != null) {
      resetAutoCommit();
      if (log.isDebugEnabled()) {
        log.debug("Closing JDBC Connection [" + connection + "]");
      }
      connection.close();
    }
  }
  // 省略部分代码......
}
复制代码
 
从JdbcTransaction类的源代码可以看出,JdbcTransaction就是使用java.sql.Connection 上的commit、rollback功能来完成事务操作的。
 
 
5. ManagedTransaction
ManagedTransaction让容器来管理事务Transaction的整个生命周期,意思就是说,使用ManagedTransaction的commit和rollback功能不会对事务有任何的影响,它什么都不会做,它将事务管理的权力移交给了容器来实现。ManagedTransaction的代码实现如下:
 
/**
* 让容器管理事务transaction的整个生命周期
* connection的获取延迟到getConnection()方法调用时
* 忽略所有的commit和rollback操作
* 默认情况下,可以关闭一个连接connection,也可以配置它不可以关闭一个连接
* 让容器来管理transaction的整个生命周期
* @see ManagedTransactionFactory
*/
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 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();
    }
  }
  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());
    }
  }
}
复制代码
 
从ManagedTransaction类的源代码可以看出,提交和回滚时它什么都没有做,所以,当使用ManagedTransaction时MyBatis的事务是交给容器来操作管理的。