Spring 事务传播机制、隔离级别以及事务执行流程源码结合案例分析(上)

简介: Spring 事务传播机制、隔离级别以及事务执行流程源码结合案例分析

前言

了解整个事务的执行过程,那么就必须要要先了解事务的传播特性、隔离级别基础知识,以此为前提,才能知晓其下是如何贯通在一起使用的

传播特性简要

传播特性有以下七种,传播属性默认值为 REQUIRED:当前存在事务,就使用当前事务,否则创建一个新的事务

隔离级别简要

事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:

  • 脏读:一个事务读到另一个事务未提交的更新数据,所谓脏读,就是指事务A读到了事务 B 还没有提交的数据,比如银行取钱,事务 A 开启事务,此时切换到事务 B,事务 B 开启事务–>取走100元,此时切换回事务 A,事务A读取的肯定是数据库里面的原始数据,因为事务 B 取走了 100 块钱,并没有提交,数据库里面的账务余额肯定还是原始余额,这就是脏读
  • 幻读:指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象 发生了幻觉一样
  • 不可重复读:在一个事务里面的操作中发现了未被操作的数据,比方说在同一个事务中先后执行两条一模一样的 select 语句,期间在此次事务中没有执行过任何 DDL 语句,但先后得到的结果不一致,这就是不可重复读

Spring 中支持的隔离级别

  • DEFAULT:使用数据库本身使用的隔离级别->ORACLE(读已提交)、 MySQL(可重复读)
  • READ_UNCOMITTED:读未提交(脏读)最低的隔离级别,一切皆有可能
  • READ_COMMITED:读已提交,ORACLE默认隔离级别,有幻读以及不可重复读风险
  • REPEATABLE_READ:可重复读,解决不可重复读的隔离级别,但还是有幻读风险
  • SERLALIZABLE:串行化,最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,这样就解决了脏读、不可重复读和幻读的问题了

再必须强调一遍,不是事务隔离级别设置得越高越好,事务隔离级别设置得越高,意味着势必要花手段去加锁用以保证事务的正确性,那么效率就要降低,因此实际开发中往往要在效率和并发正确性之间做一个取舍,一般情况下会设置为 READ_COMMITED,此时避免了脏读,并发性也还不错,之后再通过一些别的手段去解决不可重复读和幻读的问题就好了

如何设计一个事务系统

如果交给我们自己来设计一个事务系统时,一般分以下几个批次进行处理

  • 创建一个事务并且提前将事务的基本信息准备好,包括:事务属性、状态、管理器信息、数据库连接
  • 执行我们程序内部的业务逻辑
  • 判定在程序运行时是否发生了异常
  • 如果没发生异常,事务正常执行,并且将事务相关信息给清除,避免资源的消耗,commit 提交事务
  • 如果发生了异常,事务异常执行,清除事务的相关信息,并且恢复到事务前的一个状态,rollback 回滚事务
  • 最终完成事务的整个过程,最终释放数据库连接

事务执行流程 source coding

在执行程序业务逻辑前,如果其被事务代理所修饰,会代理执行 DynamicAdvisedInterceptor#intercept 方法,获取到拦截器责任链 advisor 后,链式调用 proceed 方法;整个事务处理过程中,包含了以下 advisor

  • ExposeInovacationInterceptor :为了方便责任链的调用,作为前驱,联系者,协调其他 advisor 的运行
  • DefaultBeanFactoryPointcutAdvisor:其父类为 AbstractBeanFactoryPointcutAdvisor,内部拥有 advice,会在组装拦截器时调用 getAdvice 方法获取到 TransactionInterceptor 拦截器
  • 最后组装完以后的拦截器链:ExposeInovacationInterceptor —> TransactionInterceptor

核心类 TransactionInfo

protected static final class TransactionInfo {
  @Nullable
  private final PlatformTransactionManager transactionManager; // 事务管理器
  @Nullable
  private final TransactionAttribute transactionAttribute; // 事务属性:传播机制、隔离级别、超时时间、是否只读
  private final String joinpointIdentification;
  @Nullable
  private TransactionStatus transactionStatus; // 事务状态:是否为新事务、是否是需要新同步、挂起的连接资源
  @Nullable
  private TransactionInfo oldTransactionInfo; // 同一个线程内旧的事务信息
  public TransactionInfo(@Nullable PlatformTransactionManager transactionManager,
                         @Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {
    this.transactionManager = transactionManager;
    this.transactionAttribute = transactionAttribute;
    this.joinpointIdentification = joinpointIdentification;
  }
  public PlatformTransactionManager getTransactionManager() {
    Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
    return this.transactionManager;
  }
  @Nullable
  public TransactionAttribute getTransactionAttribute() {
    return this.transactionAttribute;
  }
  // 获取方法的全限定名称
  public String getJoinpointIdentification() {
    return this.joinpointIdentification;
  }
  public void newTransactionStatus(@Nullable TransactionStatus status) {
    this.transactionStatus = status;
  }
  @Nullable
  public TransactionStatus getTransactionStatus() {
    return this.transactionStatus;
  }
  // 是否存在事务
  public boolean hasTransaction() {
    return (this.transactionStatus != null);
  }
  private void bindToThread() {
    // 暴露当前的事务状态,将存在的事务进行挂起,等待当前事务完成后再将已存在的事务进行恢复
    this.oldTransactionInfo = transactionInfoHolder.get();
    transactionInfoHolder.set(this);
  }
  private void restoreThreadLocalStatus() {
    // 将老的事务状态进行重新设定
    transactionInfoHolder.set(this.oldTransactionInfo);
  }
  @Override
  public String toString() {
    return (this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction");
  }
}

调用事务方法的入口会到达 TransactionInterceptor#invoke#invokeWithinTransaction(以事务的方式调用目标方法,在这埋了一个钩子函数,用来回调目标方法的)事务的整个处理逻辑如下:

  • prepare 准备工作:作好事务需要的前期准备工作,获取当前的事务属性源信息以及事务管理器转换为 PlatformTransactionManager 类型「其提供三种能力:1、获取事务状态对象;2、提交事务;3、回滚事务」最后获取该方法的全限定方法名
  • 创建事务信息:createTransactionIfNecessary,先根据当前的事务属性创建委托类「DelegatingTransactionAttribute」
  • 根据事务属性委托类创建事务状态信息,分为以下几种情况
  • doGetTransaction:获取事务对象信息,默认第一次进来的是没有值的;它主要是从 TransactionSynchronizationManager 事务同步管理器获取到连接持有器,设置 newConnectionHolder=false 并返回数据源事务对象
  • isExistingTransaction(transaction):判断当前线程是否存在事务连接持有器,第一次进来的都是没有连接持有器的,所以第二次方法调用时才会进来;如果当前存在事务,就处理存在事务的逻辑,先判别内层事务的传播机制

1、NERVER(从不使用事务,则存在抛出异常),则抛出异常结束

2、NOT_SUPPORTED(不支持事务) 挂起当前事务:将外层事务相关的连接持有器和属性封装为 SuspendedResourcesHolder 返回,并且创建的一个新的非事务的状态,同时将外层事务的挂起资源持有器作为参数一起进行实例化

3、REQURES_NEW(挂起已经存在的事务,开启一个新的事务):挂起当前事务后「1.清空线程本地的连接持有器;2.清空线程本地资源的所有资源信息;3.将之前的事务属性和连接器这些信息保存到 oldTransaction 变量里面;4.返回挂起的事务信息」,startTransaction:开启一个新的事务状态,同时将外层事务的挂起资源作为参数一起实例化,newTransaction、newSynchronization 属性值都为 true,开辟一个新的连接、设置好事务同步管理器中的线程本地变量「事务是否激活状态、事务的隔离级别、是否为只读事务、事务名称」

4、NESTED(存在事务就使用,不存在就创建一个新的,并且设置一个保存点):通过当前的事务再次构建一个 DefaultTransactionStatus 对象,newTransaction、newSynchronization 属性值都改为 false,并为当前创建好的事务状态对象设置一个保存点.

5、其他类型的传播机制:SUPPORTED、REQURED、MANDATORY,通过当前的事务再次构建一个 DefaultTransactionStatus 对象,newTransaction、newSynchronization 属性值都改为 false 后返回

commit 流程

如果整个事务正常执行完成,事务就需要正常提交了,执行方法:commitTransactionAfterReturning->AbstractPlatformTransactionManage#commit「处理提交,先处理保存点,然后处理新事务,如果不是新事务不会真正提交,要等外层是新事务的才提交,最后根据条件执行数据清除、线程的私有资源解绑,重置连接自动提交、隔离级别、是否只读、释放连接、恢复挂起事务等」,以下是处理提交的源码:

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
  try {
    boolean beforeCompletionInvoked = false;
    try {
      boolean unexpectedRollback = false;
      // 预留
      prepareForCommit(status);
      // 添加 TransactionSynchronization 中的对应方法的调用
      triggerBeforeCommit(status);
      // 提交完成前回调
      triggerBeforeCompletion(status);
      beforeCompletionInvoked = true;
      // 有保存点
      if (status.hasSavepoint()) {
        if (status.isDebug()) {
          logger.debug("Releasing transaction savepoint");
        }
        // 是否有全局回滚标记
        unexpectedRollback = status.isGlobalRollbackOnly();
        // 如果存在保存点则清除保存点信息
        status.releaseHeldSavepoint();
      }
      // 当前状态是新事务
      else if (status.isNewTransaction()) {
        if (status.isDebug()) {
          logger.debug("Initiating transaction commit");
        }
        unexpectedRollback = status.isGlobalRollbackOnly();
        // 如果是独立的事务则直接提交
        doCommit(status);
      }
      else if (isFailEarlyOnGlobalRollbackOnly()) {
        unexpectedRollback = status.isGlobalRollbackOnly();
      }
      // 有全局回滚标记就报异常
      if (unexpectedRollback) {
        throw new UnexpectedRollbackException(
          "Transaction silently rolled back because it has been marked as rollback-only");
      }
    }
    catch (UnexpectedRollbackException ex) {
      // can only be caused by doCommit
      triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
      throw ex;
    }
    catch (TransactionException ex) {
      // can only be caused by doCommit
      if (isRollbackOnCommitFailure()) {
        doRollbackOnCommitException(status, ex);
      }
      else {
        triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
      }
      throw ex;
    }
    catch (RuntimeException | Error ex) {
      if (!beforeCompletionInvoked) {
        triggerBeforeCompletion(status);
      }
      // 提交过程中出现异常则回滚
      doRollbackOnCommitException(status, ex);
      throw ex;
    }
    try {
      // 提交后回调
      triggerAfterCommit(status);
    }
    finally {
      // 提交后清除线程私有同步状态
      triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
    }
  }
  finally {
    //根据条件,完成后数据清除,和线程的私有资源解绑,重置连接自动提交,隔离级别,是否只读,释放连接,恢复挂起事务等
    cleanupAfterCompletion(status);
  }
}

无论是正常提交或者发生了异常,一些基本的资源应该被释放,清除当前的事务信息,恢复线程本地老的事务信息

private void restoreThreadLocalStatus() {
  transactionInfoHolder.set(this.oldTransactionInfo);
}


目录
相关文章
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
人工智能 Cloud Native 安全
DeepSeek + Higress AI 网关/Spring AI Alibaba 案例征集
诚挚地感谢每一位持续关注并使用 Higress 和 Spring AI Alibaba 的朋友,DeepSeek + Higress AI 网关/Spring AI Alibaba 案例征集中。
1175 125
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
839 70
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
1327 1
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
1567 0
|
负载均衡 Java API
基于 Spring Cloud 的微服务架构分析
Spring Cloud 是一个基于 Spring Boot 的微服务框架,提供全套分布式系统解决方案。它整合了 Netflix、Zookeeper 等成熟技术,通过简化配置和开发流程,支持服务发现(Eureka)、负载均衡(Ribbon)、断路器(Hystrix)、API网关(Zuul)、配置管理(Config)等功能。此外,Spring Cloud 还兼容 Nacos、Consul、Etcd 等注册中心,满足不同场景需求。其核心组件如 Feign 和 Stream,进一步增强了服务调用与消息处理能力,为开发者提供了一站式微服务开发工具包。
1156 0
|
IDE Java 应用服务中间件
spring boot 启动流程
Spring Boot 启动流程简介: 在使用 Spring Boot 之前,启动 Java Web 应用需要配置 Web 容器(如 Tomcat),并将应用打包放入容器目录。而使用 Spring Boot,只需运行 main() 方法即可启动 Web 应用。Spring Boot 的核心启动方法是 SpringApplication.run(),它负责初始化和启动应用上下文。 主要步骤包括: 1. **应用启动计时**:使用 StopWatch 记录启动时间。 2. **打印 Banner**:显示 Spring Boot 的 LOGO。 3. **创建上下文实例**:通过反射创建
990 5
|
SQL 前端开发 Java
深入分析 Spring Boot 项目开发中的常见问题与解决方案
本文深入分析了Spring Boot项目开发中的常见问题与解决方案,涵盖视图路径冲突(Circular View Path)、ECharts图表数据异常及SQL唯一约束冲突等典型场景。通过实际案例剖析问题成因,并提供具体解决方法,如优化视图解析器配置、改进数据查询逻辑以及合理使用外键约束。同时复习了Spring MVC视图解析原理与数据库完整性知识,强调细节处理和数据验证的重要性,为开发者提供实用参考。
669 0
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
773 7