Mybatis管理事务是分为两种方式:

(1)使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
(2)使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,而是让程序的容器(JBOSS,WebLogic)来实现对事务的管理
在Mybatis的配置文件中可以配置事务管理方式如下:
[html]  view plain  copy
 print ?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.  <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">  
  3.  <configuration>  
  4.      <environments default="development">  
  5.           <environment id="development">  
  6.               <!--配置事务的管理方式-->  
  7.               <transactionManager type="JDBC" />  
  8.               <!-- 配置数据库连接信息 -->  
  9.               <dataSource type="POOLED">  
  10.                   <property name="driver" value="com.mysql.jdbc.Driver" />  
  11.                  <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />  
  12.                  <property name="username" value="root" />  
  13.                  <property name="password" value="XDP" />  
  14.              </dataSource>  
  15.          </environment>  
  16.      </environments>      
  17.  </configuration>  
Mybatis提供了一个事务接口Transaction,以及两个实现类jdbcTransaction和ManagedTransaction,当spring与Mybatis一起使用时,spring提供了一个实现类SpringManagedTransaction
Transaction接口:提供的抽象方法有获取数据库连接getConnection,提交事务commit,回滚事务rollback和关闭连接close,源码如下:
[java]  view plain  copy
 print ?
  1. //事务接口  
  2. ublic interface Transaction {  
  3.  /** 
  4.   * Retrieve inner database connection 
  5.   * @return DataBase connection 
  6.   * @throws SQLException 
  7.   */  
  8.   //获得数据库连接  
  9.  Connection getConnection() throws SQLException;  
  10.  /** 
  11.   * 提交 
  12.   * Commit inner database connection. 
  13.   * @throws SQLException 
  14.   */  
  15.  void commit() throws SQLException;  
  16.  /** 
  17.   * 回滚 
  18.   * Rollback inner database connection. 
  19.   * @throws SQLException 
  20.   */  
  21.  void rollback() throws SQLException;  
  22.  /** 
  23.   * 关闭连接 
  24.   * Close inner database connection. 
  25.   * @throws SQLException 
  26.   */  
  27.  void close() throws SQLException;  

1)JdbcTransaction实现类:Transaction的实现类,通过使用jdbc提供的方式来管理事务,通过Connection提供的事务管理方法来进行事务管理,源码如下:
[java]  view plain  copy
 print ?
  1. public class JdbcTransaction implements Transaction {  
  2.   
  3.   private static final Log log = LogFactory.getLog(JdbcTransaction.class);  
  4.   
  5.   /* 连接**/  
  6.   protected Connection connection;  
  7.     
  8.   /* 数据源**/  
  9.   protected DataSource dataSource;  
  10.     
  11.   /* 事务等级**/  
  12.   protected TransactionIsolationLevel level;  
  13.     
  14.   /* 事务提交**/  
  15.   protected boolean autoCommmit;  
  16.   
  17.   public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {  
  18.     dataSource = ds;  
  19.     level = desiredLevel;  
  20.     autoCommmit = desiredAutoCommit;  
  21.   }  
  22.   
  23.   public JdbcTransaction(Connection connection) {  
  24.     this.connection = connection;  
  25.   }  
  26.   
  27.   @Override  
  28.   public Connection getConnection() throws SQLException {  
  29.     if (connection == null) {  
  30.       openConnection();  
  31.     }  
  32.     //返回连接  
  33.     return connection;  
  34.   }  
  35.   
  36.   @Override  
  37.   public void commit() throws SQLException {  
  38.     if (connection != null && !connection.getAutoCommit()) {  
  39.       if (log.isDebugEnabled()) {  
  40.         log.debug("Committing JDBC Connection [" + connection + "]");  
  41.       }  
  42.       //连接提交  
  43.       connection.commit();  
  44.     }  
  45.   }  
  46.   
  47.   @Override  
  48.   public void rollback() throws SQLException {  
  49.     if (connection != null && !connection.getAutoCommit()) {  
  50.       if (log.isDebugEnabled()) {  
  51.         log.debug("Rolling back JDBC Connection [" + connection + "]");  
  52.       }  
  53.       //连接回滚  
  54.       connection.rollback();  
  55.     }  
  56.   }  
  57.   
  58.   @Override  
  59.   public void close() throws SQLException {  
  60.     if (connection != null) {  
  61.       resetAutoCommit();  
  62.       if (log.isDebugEnabled()) {  
  63.         log.debug("Closing JDBC Connection [" + connection + "]");  
  64.       }  
  65.       //关闭连接  
  66.       connection.close();  
  67.     }  
  68.   }  
  69.   
  70.   protected void setDesiredAutoCommit(boolean desiredAutoCommit) {  
  71.     try {  
  72.       //事务提交状态不一致时修改  
  73.       if (connection.getAutoCommit() != desiredAutoCommit) {  
  74.         if (log.isDebugEnabled()) {  
  75.           log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");  
  76.         }  
  77.         connection.setAutoCommit(desiredAutoCommit);  
  78.       }  
  79.     } catch (SQLException e) {  
  80.       // Only a very poorly implemented driver would fail here,  
  81.       // and there's not much we can do about that.  
  82.       throw new TransactionException("Error configuring AutoCommit.  "  
  83.           + "Your driver may not support getAutoCommit() or setAutoCommit(). "  
  84.           + "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);  
  85.     }  
  86.   }  
  87.   
  88.   protected void resetAutoCommit() {  
  89.     try {  
  90.       if (!connection.getAutoCommit()) {  
  91.         // MyBatis does not call commit/rollback on a connection if just selects were performed. select操作没有commit和rollback事务  
  92.         // Some databases start transactions with select statements 一些数据库在select操作是会开启事务  
  93.         // and they mandate a commit/rollback before closing the connection.  
  94.         // A workaround is setting the autocommit to true before closing the connection.  
  95.         // Sybase throws an exception here.  
  96.         if (log.isDebugEnabled()) {  
  97.           log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");  
  98.         }  
  99.         connection.setAutoCommit(true);  
  100.       }  
  101.     } catch (SQLException e) {  
  102.       if (log.isDebugEnabled()) {  
  103.         log.debug("Error resetting autocommit to true "  
  104.           + "before closing the connection.  Cause: " + e);  
  105.       }  
  106.     }  
  107.   }  
  108.   //打开连接  
  109.   protected void openConnection() throws SQLException {  
  110.     if (log.isDebugEnabled()) {  
  111.       log.debug("Opening JDBC Connection");  
  112.     }  
  113.     //从数据源中获得连接  
  114.     connection = dataSource.getConnection();  
  115.     if (level != null) {  
  116.       connection.setTransactionIsolation(level.getLevel());  
  117.     }  
  118.     setDesiredAutoCommit(autoCommmit);  
  119.   }  
  120.   
  121. }  

2)ManagedTransaction实现类:通过容器来进行事务管理,所有它对事务提交和回滚并不会做任何操作,源码如下:
[java]  view plain  copy
 print ?
  1. public class ManagedTransaction implements Transaction {  
  2.   
  3.   private static final Log log = LogFactory.getLog(ManagedTransaction.class);  
  4.   
  5.   private DataSource dataSource;  
  6.   private TransactionIsolationLevel level;  
  7.   private Connection connection;  
  8.   private boolean closeConnection;  
  9.   
  10.   public ManagedTransaction(Connection connection, boolean closeConnection) {  
  11.     this.connection = connection;  
  12.     this.closeConnection = closeConnection;  
  13.   }  
  14.   //数据源,事务等级及是否关闭事务  
  15.   public ManagedTransaction(DataSource ds, TransactionIsolationLevel level, boolean closeConnection) {  
  16.     this.dataSource = ds;  
  17.     this.level = level;  
  18.     this.closeConnection = closeConnection;  
  19.   }  
  20.   
  21.   @Override  
  22.   public Connection getConnection() throws SQLException {  
  23.     if (this.connection == null) {  
  24.       openConnection();  
  25.     }  
  26.     return this.connection;  
  27.   }  
  28.   //提交操作无效  
  29.   @Override  
  30.   public void commit() throws SQLException {  
  31.     // Does nothing  
  32.   }  
  33.   //回滚操作无效  
  34.   @Override  
  35.   public void rollback() throws SQLException {  
  36.     // Does nothing  
  37.   }  
  38.   
  39.   @Override  
  40.   public void close() throws SQLException {  
  41.     if (this.closeConnection && this.connection != null) {  
  42.       if (log.isDebugEnabled()) {  
  43.         log.debug("Closing JDBC Connection [" + this.connection + "]");  
  44.       }  
  45.       //关闭连接  
  46.       this.connection.close();  
  47.     }  
  48.   }  
  49.   
  50.   protected void openConnection() throws SQLException {  
  51.     if (log.isDebugEnabled()) {  
  52.       log.debug("Opening JDBC Connection");  
  53.     }  
  54.     this.connection = this.dataSource.getConnection();  
  55.     if (this.level != null) {  
  56.       this.connection.setTransactionIsolation(this.level.getLevel());  
  57.     }  
  58.   }  
  59.   
  60. }  
注意:如果我们使用MyBatis构建本地程序,即不是WEB程序,若将type设置成"MANAGED",那么,我们执行的任何update操作,即使我们最后执行了commit操作,数据也不会保留,不会对数据库造成任何影响。因为我们将MyBatis配置成了“MANAGED”,即MyBatis自己不管理事务,而我们又是运行的本地程序,没有事务管理功能,所以对数据库的update操作都是无效的。

3)SpringManagedTransaction实现类:它其实也是通过使用JDBC来进行事务管理的,当spring的事务管理有效时,不需要操作commit/rollback/close,spring事务管理会自动帮我们完成,源码如下:
[java]  view plain  copy
 print ?
  1. public class SpringManagedTransaction implements Transaction {  
  2.   
  3.   private static final Log LOGGER = LogFactory.getLog(SpringManagedTransaction.class);  
  4.   
  5.   private final DataSource dataSource;  
  6.   
  7.   private Connection connection;  
  8.   
  9.   private boolean isConnectionTransactional;  
  10.   
  11.   private boolean autoCommit;  
  12.     
  13.   //获得数据源  
  14.   public SpringManagedTransaction(DataSource dataSource) {  
  15.     notNull(dataSource, "No DataSource specified");  
  16.     this.dataSource = dataSource;  
  17.   }  
  18.   
  19.   /** 
  20.    * {@inheritDoc} 
  21.    * 返回数据库连接 
  22.    */  
  23.   @Override  
  24.   public Connection getConnection() throws SQLException {  
  25.     if (this.connection == null) {  
  26.       openConnection();  
  27.     }  
  28.     return this.connection;  
  29.   }  
  30.   
  31.   /** 
  32.    * Gets a connection from Spring transaction manager and discovers if this 
  33.    * {@code Transaction} should manage connection or let it to Spring. 
  34.    * <p> 
  35.    * It also reads autocommit setting because when using Spring Transaction MyBatis 
  36.    * thinks that autocommit is always false and will always call commit/rollback 
  37.    * so we need to no-op that calls. 
  38.    *从spring的事务管理中获得一个连接  
  39.    */  
  40.   private void openConnection() throws SQLException {  
  41.     this.connection = DataSourceUtils.getConnection(this.dataSource);  
  42.     this.autoCommit = this.connection.getAutoCommit();  
  43.     this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);  
  44.   
  45.     if (LOGGER.isDebugEnabled()) {  
  46.       LOGGER.debug(  
  47.           "JDBC Connection ["  
  48.               + this.connection  
  49.               + "] will"  
  50.               + (this.isConnectionTransactional ? " " : " not ")  
  51.               + "be managed by Spring");  
  52.     }  
  53.   }  
  54.   
  55.   /** 
  56.    * {@inheritDoc} 
  57.    */  
  58.   @Override  
  59.   public void commit() throws SQLException {  
  60.     if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {  
  61.       if (LOGGER.isDebugEnabled()) {  
  62.         LOGGER.debug("Committing JDBC Connection [" + this.connection + "]");  
  63.       }  
  64.       this.connection.commit();  
  65.     }  
  66.   }  
  67.   
  68.   /** 
  69.    * {@inheritDoc} 
  70.    */  
  71.   @Override  
  72.   public void rollback() throws SQLException {  
  73.     if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {  
  74.       if (LOGGER.isDebugEnabled()) {  
  75.         LOGGER.debug("Rolling back JDBC Connection [" + this.connection + "]");  
  76.       }  
  77.       this.connection.rollback();  
  78.     }  
  79.   }  
  80.   
  81.   /** 
  82.    * {@inheritDoc} 
  83.    */  
  84.   @Override  
  85.   public void close() throws SQLException {  
  86.     DataSourceUtils.releaseConnection(this.connection, this.dataSource);  
  87.   }  
  88.   
  89. }  

Mybatis的事务管理机制还是比较简单的,其并没有做过多的操作,只是封装一下方便别人调用而已。
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐