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
本文版权归作者所有,欢迎转载,但未经作者同意不能转载,否则保留追究法律责任的权利。
目录
相关文章
|
1月前
|
XML Java 数据库连接
MyBatis的常见配置
MyBatis 常见配置包括数据库连接、类型别名、映射器等核心模块,合理配置可提升开发效率与系统性能。主要内容涵盖核心配置文件结构、关键配置项详解及配置优先级说明。
185 4
|
2月前
|
SQL XML Java
通过MyBatis的XML配置实现灵活的动态SQL查询
总结而言,通过MyBatis的XML配置实现灵活的动态SQL查询,可以让开发者以声明式的方式构建SQL语句,既保证了SQL操作的灵活性,又简化了代码的复杂度。这种方式可以显著提高数据库操作的效率和代码的可维护性。
201 18
|
7月前
|
Oracle 关系型数据库 Java
【YashanDB知识库】Mybatis-Plus适配崖山配置
【YashanDB知识库】Mybatis-Plus适配崖山配置
|
7月前
|
Java 数据库连接 微服务
微服务——MyBatis配置——事务管理
本段内容主要介绍了事务管理的两种类型:JDBC 和 MANAGED。JDBC 类型直接利用数据源连接管理事务,依赖提交和回滚机制;而 MANAGED 类型则由容器全程管理事务生命周期,例如 JEE 应用服务器上下文,默认会关闭连接,但可根据需要设置 `closeConnection` 属性为 false 阻止关闭行为。此外,提到在使用 Spring + MyBatis 时,无需额外配置事务管理器,因为 Spring 模块自带的功能可覆盖上述配置,且这两种事务管理器类型均无需设置属性。
104 0
|
7月前
|
Java 数据库连接 数据库
微服务——MyBatis配置——多环境配置
在 MyBatis 中,多环境配置允许为不同数据库创建多个 SqlSessionFactory。通过传递环境参数给 SqlSessionFactoryBuilder,可指定使用哪种环境;若忽略,则加载默认环境。`environments` 元素定义环境配置,包括默认环境 ID、事务管理器和数据源类型等。每个环境需唯一标识,确保默认环境匹配其中之一。代码示例展示了如何构建工厂及配置 XML 结构。
111 0
|
7月前
|
缓存 Java 数据库连接
微服务——MyBatis配置——常见配置
本文介绍了 MyBatis 的常见配置及其加载顺序。属性配置优先级为:方法参数传递的属性 &gt; resource/url 属性中配置 &gt; properties 元素中指定属性。同时列举了多个关键配置项,如 `cacheEnabled`(全局缓存开关)、`lazyLoadingEnabled`(延迟加载)、`useGeneratedKeys`(使用 JDBC 自动生成主键)等,并详细说明其作用、有效值及默认值。这些配置帮助开发者优化 MyBatis 的性能与行为。
105 0
|
6月前
|
SQL 存储 Java
Mybatis源码解析:详述初始化过程
以上就是MyBatis的初始化过程,这个过程主要包括SqlSessionFactory的创建、配置文件的解析和加载、映射文件的加载、SqlSession的创建、SQL的执行和SqlSession的关闭。这个过程涉及到了MyBatis的核心类和接口,包括SqlSessionFactory、SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、Configuration、SqlSession和Executor等。通过这个过程,我们可以看出MyBatis的灵活性和强大性,它可以很好地支持定制化SQL、存储过程以及高级映射,同时也避免了几
114 20
|
7月前
|
Java 数据库连接 数据库
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——MyBatis 介绍和配置
本文介绍了Spring Boot集成MyBatis的方法,重点讲解基于注解的方式。首先简述MyBatis作为持久层框架的特点,接着说明集成时的依赖导入,包括`mybatis-spring-boot-starter`和MySQL连接器。随后详细展示了`properties.yml`配置文件的内容,涵盖数据库连接、驼峰命名规范及Mapper文件路径等关键设置,帮助开发者快速上手Spring Boot与MyBatis的整合开发。
924 0
|
4月前
|
Java 数据库连接 数据库
Spring boot 使用mybatis generator 自动生成代码插件
本文介绍了在Spring Boot项目中使用MyBatis Generator插件自动生成代码的详细步骤。首先创建一个新的Spring Boot项目,接着引入MyBatis Generator插件并配置`pom.xml`文件。然后删除默认的`application.properties`文件,创建`application.yml`进行相关配置,如设置Mapper路径和实体类包名。重点在于配置`generatorConfig.xml`文件,包括数据库驱动、连接信息、生成模型、映射文件及DAO的包名和位置。最后通过IDE配置运行插件生成代码,并在主类添加`@MapperScan`注解完成整合
705 1
Spring boot 使用mybatis generator 自动生成代码插件
|
7月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于注解的整合
本文介绍了Spring Boot集成MyBatis的两种方式:基于XML和注解的形式。重点讲解了注解方式,包括@Select、@Insert、@Update、@Delete等常用注解的使用方法,以及多参数时@Param注解的应用。同时,针对字段映射不一致的问题,提供了@Results和@ResultMap的解决方案。文章还提到实际项目中常结合XML与注解的优点,灵活使用两者以提高开发效率,并附带课程源码供下载学习。
586 0