github地址:https://github.com/dchack/Mybatis-source-code-learn (欢迎star)

TransactionFactory

官方文档:

在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”):

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

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

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

提示如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器, 因为 Spring 模块会使用自带的管理器来覆盖前面的配置。

以上配置transactionManager属性来配置使用哪一种TransactionFactory的代码,肯定在MybatisXMLConfigBuilder中可以找到:

  1. private TransactionFactory transactionManagerElement(XNode context) throws Exception {
  2. if (context != null) {
  3. String type = context.getStringAttribute("type");
  4. Properties props = context.getChildrenAsProperties();
  5. TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
  6. factory.setProperties(props);
  7. return factory;
  8. }
  9. throw new BuilderException("Environment declaration requires a TransactionFactory.");
  10. }

TransactionFactory入手:

  1. public interface TransactionFactory {
  2. /**
  3. * Sets transaction factory custom properties.
  4. * @param props
  5. */
  6. void setProperties(Properties props);
  7. /**
  8. * Creates a {@link Transaction} out of an existing connection.
  9. * @param conn Existing database connection
  10. * @return Transaction
  11. * @since 3.1.0
  12. */
  13. Transaction newTransaction(Connection conn);
  14. /**
  15. * Creates a {@link Transaction} out of a datasource.
  16. * @param dataSource DataSource to take the connection from
  17. * @param level Desired isolation level
  18. * @param autoCommit Desired autocommit
  19. * @return Transaction
  20. * @since 3.1.0
  21. */
  22. Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
  23. }

TransactionFactory接口描述实现者需要从ConnectionDataSource生产org.apache.ibatis.transaction.Transaction出来。

接口实现类如下:

他们各自生产的Transaction分别是:

  • JdbcTransaction
  • ManagedTransaction
  • SpringManagedTransaction

Transaction接口:

  1. /**
  2. * Wraps a database connection.
  3. * Handles the connection lifecycle that comprises: its creation, preparation, commit/rollback and close.
  4. *
  5. * @author Clinton Begin
  6. */
  7. public interface Transaction {
  8. /**
  9. * Retrieve inner database connection
  10. * @return DataBase connection
  11. * @throws SQLException
  12. */
  13. Connection getConnection() throws SQLException;
  14. /**
  15. * Commit inner database connection.
  16. * @throws SQLException
  17. */
  18. void commit() throws SQLException;
  19. /**
  20. * Rollback inner database connection.
  21. * @throws SQLException
  22. */
  23. void rollback() throws SQLException;
  24. /**
  25. * Close inner database connection.
  26. * @throws SQLException
  27. */
  28. void close() throws SQLException;
  29. /**
  30. * Get transaction timeout if set
  31. * @throws SQLException
  32. */
  33. Integer getTimeout() throws SQLException;
  34. }

抽象出了控制connection生命周期的核心接口:getConnection(create),commit,rollback,close

JdbcTransaction的实现:

三个操作方法:commit,rollback,close,都是connection的封装而已,commit,rollback执行的条件需要已经生成好connection并且AutoCommit没有设置true,close方法会调用resetAutoCommit方法重置ConnectionautoCommit属性为true

  1. @Override
  2. public void commit() throws SQLException {
  3. if (connection != null && !connection.getAutoCommit()) {
  4. if (log.isDebugEnabled()) {
  5. log.debug("Committing JDBC Connection [" + connection + "]");
  6. }
  7. connection.commit();
  8. }
  9. }
  10. @Override
  11. public void rollback() throws SQLException {
  12. if (connection != null && !connection.getAutoCommit()) {
  13. if (log.isDebugEnabled()) {
  14. log.debug("Rolling back JDBC Connection [" + connection + "]");
  15. }
  16. connection.rollback();
  17. }
  18. }
  19. @Override
  20. public void close() throws SQLException {
  21. if (connection != null) {
  22. resetAutoCommit();
  23. if (log.isDebugEnabled()) {
  24. log.debug("Closing JDBC Connection [" + connection + "]");
  25. }
  26. connection.close();
  27. }
  28. }

重置autoCommit属性方法:

  1. protected void resetAutoCommit() {
  2. try {
  3. if (!connection.getAutoCommit()) {
  4. // MyBatis does not call commit/rollback on a connection if just selects were performed.
  5. // Some databases start transactions with select statements
  6. // and they mandate a commit/rollback before closing the connection.
  7. // A workaround is setting the autocommit to true before closing the connection.
  8. // Sybase throws an exception here.
  9. if (log.isDebugEnabled()) {
  10. log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");
  11. }
  12. connection.setAutoCommit(true);
  13. }
  14. } catch (SQLException e) {
  15. if (log.isDebugEnabled()) {
  16. log.debug("Error resetting autocommit to true "
  17. + "before closing the connection. Cause: " + e);
  18. }
  19. }
  20. }

在看下getConnection方法的实现:

  1. @Override
  2. public Connection getConnection() throws SQLException {
  3. if (connection == null) {
  4. openConnection();
  5. }
  6. return connection;
  7. }
  8. protected void openConnection() throws SQLException {
  9. if (log.isDebugEnabled()) {
  10. log.debug("Opening JDBC Connection");
  11. }
  12. connection = dataSource.getConnection();
  13. if (level != null) {
  14. connection.setTransactionIsolation(level.getLevel());
  15. }
  16. setDesiredAutoCommit(autoCommmit);
  17. }

openConnection中设置了事务隔离级别(transaction isolation level)和autoCommmit。

事务隔离级别在TransactionIsolationLevel枚举中可以看到:

  1. public enum TransactionIsolationLevel {
  2. NONE(Connection.TRANSACTION_NONE),
  3. READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),
  4. READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
  5. REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
  6. SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);
  7. private final int level;
  8. private TransactionIsolationLevel(int level) {
  9. this.level = level;
  10. }
  11. public int getLevel() {
  12. return level;
  13. }
  14. }

java.sql.Connection中的定义和注释如下:

  1. /**
  2. * A constant indicating that transactions are not supported.
  3. */
  4. int TRANSACTION_NONE = 0;
  5. /**
  6. * A constant indicating that
  7. * dirty reads, non-repeatable reads and phantom reads can occur.
  8. * This level allows a row changed by one transaction to be read
  9. * by another transaction before any changes in that row have been
  10. * committed (a "dirty read"). If any of the changes are rolled back,
  11. * the second transaction will have retrieved an invalid row.
  12. */
  13. int TRANSACTION_READ_UNCOMMITTED = 1;
  14. /**
  15. * A constant indicating that
  16. * dirty reads are prevented; non-repeatable reads and phantom
  17. * reads can occur. This level only prohibits a transaction
  18. * from reading a row with uncommitted changes in it.
  19. */
  20. int TRANSACTION_READ_COMMITTED = 2;
  21. /**
  22. * A constant indicating that
  23. * dirty reads and non-repeatable reads are prevented; phantom
  24. * reads can occur. This level prohibits a transaction from
  25. * reading a row with uncommitted changes in it, and it also
  26. * prohibits the situation where one transaction reads a row,
  27. * a second transaction alters the row, and the first transaction
  28. * rereads the row, getting different values the second time
  29. * (a "non-repeatable read").
  30. */
  31. int TRANSACTION_REPEATABLE_READ = 4;
  32. /**
  33. * A constant indicating that
  34. * dirty reads, non-repeatable reads and phantom reads are prevented.
  35. * This level includes the prohibitions in
  36. * <code>TRANSACTION_REPEATABLE_READ</code> and further prohibits the
  37. * situation where one transaction reads all rows that satisfy
  38. * a <code>WHERE</code> condition, a second transaction inserts a row that
  39. * satisfies that <code>WHERE</code> condition, and the first transaction
  40. * rereads for the same condition, retrieving the additional
  41. * "phantom" row in the second read.
  42. */
  43. int TRANSACTION_SERIALIZABLE = 8;
关于事务隔离级别

几个概念:

  • 脏读:读取的数据可以取到其他未提交事务修改的数据
  • 不可重复读:一个事务中多次读取相同的数据,因其他事务在中间修改了这个数据,导致第一个事务多次读的数据会不相同
  • 幻读:就是在一个事务提交时发现之前查的条件发生了改变

隔离级别:

  • 提交读(READ_COMMITTED)只能读取到已经提交的数据
  • 未提交读(READ_UNCOMMITTED)允许脏读
  • 可重复读(REPEATABLE_READ)在同一事务中保证多次读取的数据是一致的
  • 串行读(SERIALIZABLE)每次读都需要获取表级锁,读写互相阻塞

mysql中查看隔离级别设置:

  1. select @@global.tx_isolation;

另外我们也看到JdbcTransaction中是需要autoCommmit设置true的,否则是不能完成事务功能的。

ManagedTransaction

从类注释上可以看到:ManagedTransaction是将事务的生命周期交给容器管理,可以理解它都是空实现,比如commit,rollbackclose可以通过closeConnection字段来关闭。

SpringManagedTransaction

后续进入Mybatis扩展模块时展开。

Transaction-Mybatis源码的更多相关文章

  1. MyBatis 源码篇-Transaction

    本章简单介绍一下 MyBatis 的事务模块,这块内容比较简单,主要为后面介绍 mybatis-spring-1.**.jar(MyBatis 与 Spring 集成)中的事务模块做准备. 类图结构 ...

  2. MyBatis 源码篇-MyBatis-Spring 剖析

    本章通过分析 mybatis-spring-x.x.x.jar Jar 包中的源码,了解 MyBatis 是如何与 Spring 进行集成的. Spring 配置文件 MyBatis 与 Spring ...

  3. MyBatis 源码篇-DataSource

    本章介绍 MyBatis 提供的数据源模块,为后面与 Spring 集成做铺垫,从以下三点出发: 描述 MyBatis 数据源模块的类图结构: MyBatis 是如何集成第三方数据源组件的: Pool ...

  4. MyBatis 源码篇-插件模块

    本章主要描述 MyBatis 插件模块的原理,从以下两点出发: MyBatis 是如何加载插件配置的? MyBatis 是如何实现用户使用自定义拦截器对 SQL 语句执行过程中的某一点进行拦截的? 示 ...

  5. MyBatis 源码篇-日志模块2

    上一章的案例,配置日志级别为 debug,执行一个简单的查询操作,会将 JDBC 操作打印出来.本章通过 MyBatis 日志部分源码分析它是如何实现日志打印的. 在 MyBatis 的日志模块中有一 ...

  6. MyBatis 源码篇-日志模块1

    在 Java 开发中常用的日志框架有 Log4j.Log4j2.Apache Common Log.java.util.logging.slf4j 等,这些日志框架对外提供的接口各不相同.本章详细描述 ...

  7. MyBatis 源码篇-资源加载

    本章主要描述 MyBatis 资源加载模块中的 ClassLoaderWrapper 类和 Java 加载配置文件的三种方式. ClassLoaderWrapper 上一章的案例,使用 org.apa ...

  8. MyBatis 源码篇-SQL 执行的流程

    本章通过一个简单的例子,来了解 MyBatis 执行一条 SQL 语句的大致过程是怎样的. 案例代码如下所示: public class MybatisTest { @Test public void ...

  9. MyBatis 源码篇-整体架构

    MyBatis 的整体架构分为三层, 分别是基础支持层.核心处理层和接口层,如下图所示. 基础支持层 反射模块 该模块对 Java 原生的反射进行了良好的封装,提供了更加简洁易用的 API ,方便上层 ...

  10. MyBatis源码分析-SQL语句执行的完整流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

随机推荐

  1. kuangbin专题专题四 Silver Cow Party POJ - 3268

    题目链接:https://vjudge.net/problem/POJ-3268 题意:点X处开办排队,其他点的牛到X点去参加派对,然后从X点回到各自的点,通路是单向的,所有牛都要走最短路, 求出所有 ...

  2. django最小程序开发流程

    1.建立工程 在工程目录下打开cmd,输入以下命令.其中mysite是项目名称. django-admin startproject mysite 命令运行完后,在该目录下会出现一个名为mysite的 ...

  3. CentOS7.5搭建NFS(Network File System)

    NFS(Network File System)即网络文件系统,是由Sun公司开发的一种通过网络方式共享文件系统的通用共享解决方案.可以将远程Linux系统上的文件共享资源挂载到本地主机(Linux客 ...

  4. 到底该不该用RTOS——rtos的优点

    我现在要不要学习RTOS? 学习RTOS有什么好处? 我的项目要不要跑RTOS? ······等等一些关于RTOS的问题,其实归根结底还是你对RTOS了解的不够,项目开发的经验还不足等. 针对这部分朋 ...

  5. Futex同步机制简介

    http://blog.csdn.net/u013234805/article/details/24796551 Futex是fast userspacemutex的缩写,意思是快速用户空间互斥体.它 ...

  6. JS中判断空对象

    js 判断空对象 首先要区分一个概念,空对象和空引用: 空对象:{}是指不含任何属性的对象,当然对象属性包括字面值和函数. 空引用:obj=null 是指变量值指向null变量,当然在js默认不赋值的 ...

  7. 为什么学习JavaScript设计模式,因为它是核心

    那么什么是设计模式呢?当我们在玩游戏的时候,我们会去追求如何最快地通过,去追求获得已什么高效率的操作获得最好的奖品:下班回家,我们打开手机app查询最便捷的路线去坐车:叫外卖时候,也会找附近最近又实惠 ...

  8. uniapp 组件传参

    父组件 <v-sub @returnDate=returnDate :backGround=backGround></v-sub> import vSub from " ...

  9. K8s的存储卷使用总结

    K8s的存储卷: 它有四种存储卷: 1. emptyDir: 空目录,这种存储卷会随着Pod的删除而被清空,它一般作为缓存目录使用,或临时目录, 当做缓存目录时,通常会将一块内存空间映射到该目录上,让 ...

  10. Foxmail: 错误信息::ssl连接错误, errorCode: 5,各种解决方案的大杂烩。

    1.  收件数据过多,删除部分邮件可解决 我尝试失败,在foxmail把收件箱全部删完了没解决. 2.  网上最常见的解决方法 https://help.foxmail.com/cgi-bin/hel ...