mybatis 源码系列 组件之 Transaction

来源:互联网 发布:淘宝卖家基本设置出错 编辑:程序博客网 时间:2024/04/30 10:50

Question: 

. mybatis 对事务做了什么样的封装?

mybatis 支持的 jdbc 和 managed transaction如何实现?


事务对于数据库应用而言,是一个很重要的环节,一般有 提交,回滚 机制,同时,mybatis 抽象出了如下 事务原型:


/** * Wraps a database connection. * Handles the connection lifecycle that comprises: its creation, preparation, commit/rollback and close.  * * @author Clinton Begin */public interface Transaction {  /**   * Retrieve inner database connection   * @return DataBase connection   * @throws SQLException   */  Connection getConnection() throws SQLException;  /**   * Commit inner database connection.   * @throws SQLException   */  void commit() throws SQLException;  /**   * Rollback inner database connection.   * @throws SQLException   */  void rollback() throws SQLException;  /**   * Close inner database connection.   * @throws SQLException   */  void close() throws SQLException;}


而mybatis 对事物管理,提供了 jdbc 和 managed 两种形式:

一、使用JDBC的事务管理机制:即利用java.sql.Connection对象完成对事务的提交(commit())、回滚(rollback())、关闭(close())等

二、使用MANAGED的事务管理机制:这种机制MyBatis自身不会去实现事务管理,而是让程序的容器如(JBOSS,Weblogic)来实现对事务的管理,包括 rollback 和 commit 动作


顺便看看 ManagedTransaction 的实现: 可以知道,其不会在rollback 和 commit中做任何事情,

/** * {@link Transaction} that lets the container manage the full lifecycle of the transaction. * Delays connection retrieval until getConnection() is called. * Ignores all commit or rollback requests. * By default, it closes the connection but can be configured not to do it. * * @see ManagedTransactionFactory *//** * @author Clinton Begin */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;  }  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());    }  }}


而 JdbcTransaction 则利用 connection完成事务的管理:

/** * {@link Transaction} that makes use of the JDBC commit and rollback facilities directly. * It relies on the connection retrieved from the dataSource to manage the scope of the transaction. * Delays connection retrieval until getConnection() is called. * Ignores commit or rollback requests when autocommit is on. * * @see JdbcTransactionFactory *//** * @author Clinton Begin */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;  }  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);  }}


为了方便建立事务,mybatis提供了 事务工厂,同时 就两种事务管理机制,分别由 具体的 工厂类来实现:


如下为 TransactionFactory 接口

/** * Creates {@link Transaction} instances. * * @author Clinton Begin */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   */  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   */  Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);}


如下为 ManagedTransactionFactory实现:

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


如下为 JdbcTransactionFactory 的实现:

public class JdbcTransactionFactory implements TransactionFactory {  public void setProperties(Properties props) {  }  public Transaction newTransaction(Connection conn) {    return new JdbcTransaction(conn);  }  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {    return new JdbcTransaction(ds, level, autoCommit);  }}




0 0
原创粉丝点击