博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
mybatis源码解读(四)——事务的配置
阅读量:6374 次
发布时间:2019-06-23

本文共 10709 字,大约阅读时间需要 35 分钟。

  上一篇博客我们介绍了mybatis中关于,本篇博客介绍mybatis的事务管理。

  对于事务,我们是在mybatis-configuration.xml 文件中配置的:

  

  关于解析 <environments />标签在上一篇数据源的配置我们已经介绍了,不了解的可以参考上篇博客。

1、mybatis 支持的事务类图

  mybatis 支持的所有事务的所有类都在如下包中:

  

  下面通过类图来理解该包中所有类的关系:

  

2、mybatis 支持的两种事务类型管理器

  通过配置文件中的 type 属性:

  我们可以配置不同的事务管理器来管理事务。在mybatis中支持两种事务类型管理器,分别是:

  ①、type = "JDBC":这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。

  ②、type="MANAGED":这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。例如:

1 
2
3

  注意:和数据源配置一样,通常项目中我们不会单独使用 mybatis 来管理事务。比如选择框架 Spring +mybatis,这时候没有必要配置事务管理器, 因为 Spring 模块会使用自带的管理器来覆盖前面的配置。

  再回头看看在 mybatis 的 org.apache.ibatis.transaction 包下的所有类,也就是上面的类图。mybatis的事务首先会定义一个事务接口 Transaction,

3、初始化事务管理器

  我们说事务(Transaction),一般是指要做的或所做的事情。在数据库中,事务具有如下四个属性:

  ①、原子性(atomicity):一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。

  ②、一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

  ③、隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

  ④、持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

  这也就是常说的事务 ACID 特性。而在程序中,对于事务的操作通常是:

  1、创建事务(create)

  2、提交事务(commit)

  3、回滚事务(rollback)

  4、关闭事务(close)

  在mybatis的 org.apache.ibatis.transaction 包下的 Transaction 接口便为我们定义了这一套操作:

  

1 /** 2  *    Copyright 2009-2016 the original author or authors. 3  * 4  *    Licensed under the Apache License, Version 2.0 (the "License"); 5  *    you may not use this file except in compliance with the License. 6  *    You may obtain a copy of the License at 7  * 8  *       http://www.apache.org/licenses/LICENSE-2.0 9  *10  *    Unless required by applicable law or agreed to in writing, software11  *    distributed under the License is distributed on an "AS IS" BASIS,12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13  *    See the License for the specific language governing permissions and14  *    limitations under the License.15  */16 package org.apache.ibatis.transaction;17 18 import java.sql.Connection;19 import java.sql.SQLException;20 21 /**22  * Wraps a database connection.23  * Handles the connection lifecycle that comprises: its creation, preparation, commit/rollback and close. 24  *25  * @author Clinton Begin26  */27 public interface Transaction {28 29   /**30    * Retrieve inner database connection31    * @return DataBase connection32    * @throws SQLException33    */34   Connection getConnection() throws SQLException;35 36   /**37    * Commit inner database connection.38    * @throws SQLException39    */40   void commit() throws SQLException;41 42   /**43    * Rollback inner database connection.44    * @throws SQLException45    */46   void rollback() throws SQLException;47 48   /**49    * Close inner database connection.50    * @throws SQLException51    */52   void close() throws SQLException;53 54   /**55    * Get transaction timeout if set56    * @throws SQLException57    */58   Integer getTimeout() throws SQLException;59   60 }
View Code

  同时,mybatis为了获取事务采用了工厂模式,定义了一个工厂接口:TransactionFactory

  

  通过实现该工厂接口,mybatis提供了两种不同的事务管理器:

  

  这两种事务管理器的获取也是采用了工厂模式。下面我们来分别看看这两种事务管理器。

4、JdbcTransaction

  当在配置文件中配置:type = "JDBC"时,就是用 JdbcTransaction 来管理事务。使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。

  代码如下:

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

5、ManagedTransaction

  ManagedTransaction的代码实现几乎都是一个空的方法,它选择让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。

1 /**  2  *    Copyright 2009-2016 the original author or authors.  3  *  4  *    Licensed under the Apache License, Version 2.0 (the "License");  5  *    you may not use this file except in compliance with the License.  6  *    You may obtain a copy of the License at  7  *  8  *       http://www.apache.org/licenses/LICENSE-2.0  9  * 10  *    Unless required by applicable law or agreed to in writing, software 11  *    distributed under the License is distributed on an "AS IS" BASIS, 12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13  *    See the License for the specific language governing permissions and 14  *    limitations under the License. 15  */ 16 package org.apache.ibatis.transaction.managed; 17  18 import java.sql.Connection; 19 import java.sql.SQLException; 20 import javax.sql.DataSource; 21  22 import org.apache.ibatis.logging.Log; 23 import org.apache.ibatis.logging.LogFactory; 24 import org.apache.ibatis.session.TransactionIsolationLevel; 25 import org.apache.ibatis.transaction.Transaction; 26  27 /** 28  * {
@link Transaction} that lets the container manage the full lifecycle of the transaction. 29 * Delays connection retrieval until getConnection() is called. 30 * Ignores all commit or rollback requests. 31 * By default, it closes the connection but can be configured not to do it. 32 * 33 * @author Clinton Begin 34 * 35 * @see ManagedTransactionFactory 36 */ 37 public class ManagedTransaction implements Transaction { 38 39 private static final Log log = LogFactory.getLog(ManagedTransaction.class); 40 41 private DataSource dataSource; 42 private TransactionIsolationLevel level; 43 private Connection connection; 44 private boolean closeConnection; 45 46 public ManagedTransaction(Connection connection, boolean closeConnection) { 47 this.connection = connection; 48 this.closeConnection = closeConnection; 49 } 50 51 public ManagedTransaction(DataSource ds, TransactionIsolationLevel level, boolean closeConnection) { 52 this.dataSource = ds; 53 this.level = level; 54 this.closeConnection = closeConnection; 55 } 56 57 @Override 58 public Connection getConnection() throws SQLException { 59 if (this.connection == null) { 60 openConnection(); 61 } 62 return this.connection; 63 } 64 65 @Override 66 public void commit() throws SQLException { 67 // Does nothing 68 } 69 70 @Override 71 public void rollback() throws SQLException { 72 // Does nothing 73 } 74 75 @Override 76 public void close() throws SQLException { 77 if (this.closeConnection && this.connection != null) { 78 if (log.isDebugEnabled()) { 79 log.debug("Closing JDBC Connection [" + this.connection + "]"); 80 } 81 this.connection.close(); 82 } 83 } 84 85 protected void openConnection() throws SQLException { 86 if (log.isDebugEnabled()) { 87 log.debug("Opening JDBC Connection"); 88 } 89 this.connection = this.dataSource.getConnection(); 90 if (this.level != null) { 91 this.connection.setTransactionIsolation(this.level.getLevel()); 92 } 93 } 94 95 @Override 96 public Integer getTimeout() throws SQLException { 97 return null; 98 } 99 100 }

 

 

 

 

  

  

 

转载地址:http://dojqa.baihongyu.com/

你可能感兴趣的文章
mac nginx php-fpm,Mac系统下搭建Nginx+php-fpm
查看>>
java策略模式使用场景,Java设计模式—策略模式
查看>>
oracle时钟,oracle RAC环境中系统时钟的调整
查看>>
oracle数据库体系结构ppt,Oracle数据库的体系结构
查看>>
linux 虚拟目录映射,IIS7添加虚拟目录映射另一台服务器的共享文件夹
查看>>
linux杀一个awk查出的进程,Linux shell - 找到进程pid,然后杀掉(jps, grep, awk)
查看>>
linux内核模块获取进程pid,内核模块打印进程线程PID信息
查看>>
linux共享文件夹sumba,linux 的 samba 实现共享文件夹
查看>>
linux查看设备使用状况,linux下查看硬件资源和网络资源的使用情况
查看>>
centos linux终端,CentOS7 Linux系统命令
查看>>
ip核在linux的驱动,基于嵌入式Linux的USBOTG IP核驱动的设计与实现
查看>>
嵌入式linux系统网络通信,基于嵌入式Linux系统中网络通信研究与实现
查看>>
vmware linux 无网络配置文件,vmware虚拟机添加新网卡后,/etc/sysconfig/network-scripts/下无配置文件ifcfg-xxxx...
查看>>
linux yum库地址,Linux 搭建本地yum仓库
查看>>
linux python htmlparser 安装,python pycparser安装程序
查看>>
linux调用接口带参数,系统调用之二:参数传递
查看>>
ubunt Linux nginx,Ubuntu下安装Nginx
查看>>
存储器动态分区算法c语言,动态分区分配算法的详细过程
查看>>
c语言程序中计算圆的面积,C代码:使用概率的方法计算圆的面积
查看>>
2017年九月c语言考试成绩,2017年9月计算机二级C语言操作题
查看>>