Spring数据库事务的实现机制讲解

目录
  • 事务控制的核心——Connection
  • 用AOP技术保持当前的Connection
  • Service层和Dao层共享Connection
  • 事务为什么要切在Service层的理由
  • spring事务与数据库事务的区别

事务控制的核心——Connection

在开始之前,先让我们回忆一下数据库较原始的JDBC是怎么管理事务的:

    //仅做演示,代码不完整,不完全规范
    try {
        con.setAutoCommit(false);
        statement1 = con.prepareStatement(sql);
        statement1.executeUpdate();
        statement2 = con.prepareStatement(sql1);
        statement2.executeUpdate();
        con.commit();
    } catch (SQLException e) {
        try {
            con.rollback();
        } catch (SQLException e1) {
        }
    }

可以很明显的看到,JDBC框架下的事务控制是由connection完成的。因为不论是MyBatis还是MyBatis-Spring都是在JDBC框架基础上的高层框架,所以他们的原理仍然应该是一致的,也就是说想控制事务,必须要控制Connection。

我们常说事务要切在Service层,所以连接需要在整个Service请求中都是同一个,不能变。

用AOP技术保持当前的Connection

Spring的事务管理就是使用AOP技术,通过对Service层设置切面,注入事务管理的逻辑。

Spring的事务管理切面配置采用了声明式事务,最常用的两种方法是 tx:Advice 和 tx:annotation-driven 两种方式。

两种方式的配置文件解析器分别是:

org.springframework.transaction.config.TxAdviceBeanDefinitionParser

org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser

细看其中的代码和配置内容,就会发现,不论哪种方式都会创建包含事务处理功能的动态代理。代理关联的切面(Advice)类是 TransactionInterceptor 。

一起看下关键代码:

   protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
            throws Throwable {
        //......
        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);//-----1.开启事务
            Object retVal = null;
            try {
                retVal = invocation.proceedWithInvocation();//...2.执行被代理的请求
            }
            catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, ex);//...3.异常回滚
                throw ex;
            }
            finally {
                cleanupTransactionInfo(txInfo);
            }
            commitTransactionAfterReturning(txInfo);//...4.提交事务
            return retVal;
        }
        //......

上边的代码里是不是没有看到TransactionManger和Connection?那么这两个东西的作用在哪里呢?

TransactionManger是上述TransactionInterceptor的一个属性(不严的说),主要作用是用来创建connection,创建之后的Connection会被保存在TransactionInfo里面。

TransactionInfo在上述代码片段中被后续传递给事务提交和事务回滚的代码。

Service层和Dao层共享Connection

我们都知道事务要切在Service层,也就是说上一节的切面只是在Service层有效,那么Dao层怎么获取到Connection连接呢?

如果Service层和Dao层的连接不是一个连接那么回滚和提交操作就等同于无效了!

这里只用MyBatis来说明,其他的ORM框架实现原理基本也是一样的。

要明白这一点需要先弄明白MyBatis本身的事务管理机制,可以参考MyBatis源码解析之Transaction事务模块。MyBatis提供了两种事务管理机制一种是自己内部用的JDBC模式,一种是支持代理给外部控制的MANAGED模式。

第二种模式下会把事务的交给外部控制,外部只需要提供一个实现了 org.apache.ibatis.transaction.Transaction 接口的控制类即可。

一起来看一下Transaction需要提供哪些方法:

public interface Transaction {
  Connection getConnection() throws SQLException;
  void commit() throws SQLException;
  void rollback() throws SQLException;
  void close() throws SQLException;
}

注意里边的getConnection方法,也就是说MyBatis的连接也是交给外部来获取的!!那么只需要想办法把Service层的Connection存起来,然后让自己实现Transaction获取到即可。

Spring采用的是ThreadLocal本地线程变量的技术来做到的,我们可以看下mybatis-spring的 org.mybatis.spring.transaction.SpringManagedTransaction 中getConnection的实现就明白了:

  public Connection getConnection() throws SQLException {
    if (this.connection == null) {
      openConnection();
    }
    return this.connection;
  }

  private void openConnection() throws SQLException {
    this.connection = DataSourceUtils.getConnection(this.dataSource);//...1.关键点在这里!!
    this.autoCommit = this.connection.getAutoCommit();
    this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug(
          "JDBC Connection ["
              + this.connection
              + "] will"
              + (this.isConnectionTransactional ? " " : " not ")
              + "be managed by Spring");
    }
  }

其中

this.connection = DataSourceUtils.getConnection(this.dataSource); 

一行就会从ThreadLocal中拿到Connection对象。

事务为什么要切在Service层的理由

对于这个常识,有一点个人的理解:

事务的ACID要求事务要有原子性,也就是一个事务里边的多项DB操作要同时成功,同时失败,成功一半的情况是不允许的。

也就是说,一般需要事务的时候,都是包含多个功能单元的。那么我们都放在一个Dao里面就显得不那么职能分明,也就是不那么符合设计原则的单一职责原则。

spring事务与数据库事务的区别

先说一下什么是事务,事务(Transaction):

一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。。

之前一直觉得事务只针对于数据库当中,5种隔离级别,7种传播行为,后来才发现这是针对Spring的,对数据库来说隔离级别只有4种,Spring多了一个DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.

总的来说,本质上其实是同一个概念

spring的事务是对数据库的事务的封装,最后本质的实现还是在数据库,假如数据库不支持事务的话,spring的事务是没有作用的

数据库的事务说简单就只有开启,回滚和关闭,spring对数据库事务的包装,原理就是拿一个数据连接,根据spring的事务配置,操作这个数据连接对数据库进行事务开启,回滚或关闭操作.但是spring除了实现这些,还配合spring的传播行为对事务进行了更广泛的管理.其实这里还有个重要的点,那就是事务中涉及的隔离级别,以及spring如何对数据库的隔离级别进行封装.事务与隔离级别放在一起理解会更好些。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring的事务机制实例代码

    本文研究的主要是Spring的事务机制的相关内容,具体如下. JAVA EE传统事务机制 通常有两种事务策略:全局事务和局部事务.全局事务可以跨多个事务性资源(即数据源,典型的是数据库和消息队列),通常都需要J2EE应用服务器的管理,其底层需要服务器的JTA支持.而局部事务则与底层采用的持久化技术有关,如果底层直接使用JDBC,需要用Connection对象来操事务.如果采用Hibernate持久化技术,则需要使用session对象来操作事务. 通常的,使用JTA事务,JDBC事务及Hibern

  • 浅谈SpringBoot之事务处理机制

    一.Spring的事务机制 所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务.提交事务来完成数据操作,或者在发生错误的时候回滚数据. 而Spring的事务机制是用统一的机制来处理不同数据访问技术的事务处理.Spring的事务机制提供了一个PlatformTransactionManager接口,不同的数据访问技术的事务使用不同的接口实现: 在程序中定义事务管理器的代码如下: @Bean public PlatformTransactionManager transaction

  • Spring事务处理流程和原理详解

    一.事务理论学习 利用数据库事务实现应用事务控制 1.要求:同一个事务需要同一个库的同一个连接. 2. 3.分布式事务 JTA 二.spring事务处理建模 1. 2. 三.spring事务处理流程 1. 2. 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们.

  • Spring数据库事务的实现机制讲解

    目录 事务控制的核心--Connection 用AOP技术保持当前的Connection Service层和Dao层共享Connection 事务为什么要切在Service层的理由 spring事务与数据库事务的区别 事务控制的核心--Connection 在开始之前,先让我们回忆一下数据库较原始的JDBC是怎么管理事务的: //仅做演示,代码不完整,不完全规范 try { con.setAutoCommit(false); statement1 = con.prepareStatement(s

  • MySQL数据库事务transaction示例讲解教程

    目录 1.什么是事务? 2.和事务相关的语句只有这3个DML语句:insert.delete.update 3.假设所有的业务都能使用1条DML语句搞定,还需要事务机制吗? 4.事务的原理 5.事务的四大特性:ACID 6.关于事务之间的隔离性 1)第一级别:读未提交(read uncommitted) 2)第二级别:读已提交(read committed) 3)第三级别:可重复读(repeatable read) 4)第四级别:序列化读/串行化读(serializable) 7.演示事务的隔离

  • 深入了解Spring的事务传播机制

    目录 Spring 事务传播机制有哪些? 事务传播机制使用与演示 REQUIRED 使用演示 REQUIRED_NEW 使用演示 NESTED 使用演示 总结 Spring 事务传播机制是指,包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的. 既然是“事务传播”,所以事务的数量应该在两个或两个以上,Spring 事务传播机制的诞生是为了规定多个事务在传播过程中的行为的.比如方法 A 开启了事务,而在执行过程中又调用了开启事务的 B 方法,那么 B 方法的事务是应该加入到 A 事务当中

  • 老生常谈spring的事务传播机制

    目录 spring的事务传播机制 1.why 为什么会有事务传播机制? 2.传播机制生效的条件 解决方案 3.传播机制类型 PROPAGATION_REQUIRED (默认) REQUIRES_NEW (一般用在子方法需要单独事务) NESTED SUPPORTS NOT_SUPPORTED MANDATORY NEVER spring的事务传播机制 背景:实习期间几次遇到事务方法,有一次本地测试时发现事务没有回滚,就把简单描述写在wx上,今天来给spring事务做个自我总结. 1.why 为什

  • Spring框架JdbcTemplate数据库事务管理完全注解方式

    目录 Spring JdbcTemplate事务注解 配置类方式配置 完全注解方式 一.创建配置类 二.测试注解方式的事务管理 Spring JdbcTemplate事务注解 配置类方式配置 在之前的操作中,相关的配置还是写在了 xml 配置文件中.现在,使用配置类的方式进行配置. <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework

  • Spring学习JdbcTemplate数据库事务参数

    目录 Spring JdbcTemplate数据库事务参数 一.propagation 1. REQUIRED 2. REQUIRES_NEW 3. SUPPORTS 4. NOT_SUPPORTED 5. MANDATORY 6. NEVER 7. NESTED 二.ioslation 三.timeout 四.readOnly 五.rollbackFor 六.noRollbackFor Spring JdbcTemplate数据库事务参数 @Transactional() 注解里有不少参数,其

  • spring学习JdbcTemplate数据库事务管理

    目录 spring JdbcTemplate数据库事务管理 一.spring 中的事务管理 二.spring 事务管理 API 三.使用事务管理 1. 配置文件 2. 类上添加事务注解 spring JdbcTemplate数据库事务管理 现在有个账户表,里面存着用户金额. 如果要真正地做好转账的操作,就要用到事务,否则当出现异常后会出现数据不一致等问题. try { // 第一步 开启事务 // 第二步 进行业务操作 // 第三步 没有发生异常,提交事务 } catch(){ // 第四步 发

  • Spring强大事务兼容数据库多种组合解决业务需求

    目录 事物的由来 事物特性 什么事脏读.不可重复读.幻读 查询 spring事物 spring事物有哪些可配项 传播属性 事物的由来 在mysql中只有innodb存储引擎才支持事物,所以我们后续都是基于innodb来展开的 事物特性 事物是用来保证数据的完整性的,保证批量sql执行的统一性:事物具有四个特性: A(Atomicity).C(Consistency).I(Isolation).D(Durability) 原子性 一个事务(transaction)中的所有操作,要么全部完成,要么全

  • Spring框架事务属性中事务隔离级别与传播行为全面讲解

    目录 一.事务隔离级别 ①介绍 ②使用方式 二.事务传播行为 ①介绍 ②测试 一.事务隔离级别 ①介绍 数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题.一个事 务与其他事务隔离的程度称为隔离级别.SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同 的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱. 隔离级别一共有四种: 读未提交:READ UNCOMMITTED 允许Transaction01读取Transaction02未提交的修改. 读已提交

随机推荐