mybatis源码解读(四)——事务的配置

简介:   上一篇博客我们介绍了mybatis中关于数据源的配置原理,本篇博客介绍mybatis的事务管理。   对于事务,我们是在mybatis-configuration.xml 文件中配置的:      关于解析 标签在上一篇数据源的配置我们已经介绍了,不了解的可以参考上篇博客。

  上一篇博客我们介绍了mybatis中关于数据源的配置原理,本篇博客介绍mybatis的事务管理。

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

  

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

1、mybatis 支持的事务类图

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

  

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

  

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

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

<transactionManager type="JDBC" />

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

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

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

1 <transactionManager type="MANAGED">
2   <property name="closeConnection" value="false"/>
3 </transactionManager>

  注意:和数据源配置一样,通常项目中我们不会单独使用 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, 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;
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 Begin
26  */
27 public interface Transaction {
28 
29   /**
30    * Retrieve inner database connection
31    * @return DataBase connection
32    * @throws SQLException
33    */
34   Connection getConnection() throws SQLException;
35 
36   /**
37    * Commit inner database connection.
38    * @throws SQLException
39    */
40   void commit() throws SQLException;
41 
42   /**
43    * Rollback inner database connection.
44    * @throws SQLException
45    */
46   void rollback() throws SQLException;
47 
48   /**
49    * Close inner database connection.
50    * @throws SQLException
51    */
52   void close() throws SQLException;
53 
54   /**
55    * Get transaction timeout if set
56    * @throws SQLException
57    */
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   @Override
116   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 }

 

 

 

 

  

  

 

作者: YSOcean
本文版权归作者所有,欢迎转载,但未经作者同意不能转载,否则保留追究法律责任的权利。
目录
相关文章
|
3月前
|
SQL XML Java
mybatis-源码深入分析(一)
mybatis-源码深入分析(一)
|
3月前
|
Java 数据库连接 数据库
spring复习05,spring整合mybatis,声明式事务
这篇文章详细介绍了如何在Spring框架中整合MyBatis以及如何配置声明式事务。主要内容包括:在Maven项目中添加依赖、创建实体类和Mapper接口、配置MyBatis核心配置文件和映射文件、配置数据源、创建sqlSessionFactory和sqlSessionTemplate、实现Mapper接口、配置声明式事务以及测试使用。此外,还解释了声明式事务的传播行为、隔离级别、只读提示和事务超时期间等概念。
spring复习05,spring整合mybatis,声明式事务
|
3月前
|
SQL XML Java
mybatis复习01,简单配置让mybatis跑起来
文章介绍了MyBatis的基本概念、历史和特点,并详细指导了如何配置MyBatis环境,包括创建Maven项目、添加依赖、编写核心配置文件、创建数据表和实体类、编写Mapper接口和XML配置文件,以及如何编写工具类和测试用例。
mybatis复习01,简单配置让mybatis跑起来
|
2月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
78 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
2月前
|
Java 数据库连接 mybatis
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。
176 0
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
|
4月前
|
XML Java 数据库连接
mybatis源码研究、搭建mybatis源码运行的环境
这篇文章详细介绍了如何搭建MyBatis源码运行的环境,包括创建Maven项目、导入源码、添加代码、Debug运行研究源码,并提供了解决常见问题的方法和链接到搭建好的环境。
mybatis源码研究、搭建mybatis源码运行的环境
|
4月前
|
安全 Java 数据库连接
后端框架的学习----mybatis框架(3、配置解析)
这篇文章详细介绍了MyBatis框架的核心配置文件解析,包括环境配置、属性配置、类型别名设置、映射器注册以及SqlSessionFactory和SqlSession的生命周期和作用域管理。
后端框架的学习----mybatis框架(3、配置解析)
|
3月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
70 1
|
4月前
|
Web App开发 前端开发 关系型数据库
基于SpringBoot+Vue+Redis+Mybatis的商城购物系统 【系统实现+系统源码+答辩PPT】
这篇文章介绍了一个基于SpringBoot+Vue+Redis+Mybatis技术栈开发的商城购物系统,包括系统功能、页面展示、前后端项目结构和核心代码,以及如何获取系统源码和答辩PPT的方法。
|
4月前
|
供应链 前端开发 Java
服装库存管理系统 Mybatis+Layui+MVC+JSP【完整功能介绍+实现详情+源码】
该博客文章介绍了一个使用Mybatis、Layui、MVC和JSP技术栈开发的服装库存管理系统,包括注册登录、权限管理、用户和货号管理、库存管理等功能,并提供了源码下载链接。
服装库存管理系统 Mybatis+Layui+MVC+JSP【完整功能介绍+实现详情+源码】