那些年面试官问过我的 Spring 事务传播行为

简介: 系列文章目录前已经写了几篇文章作为本篇的铺垫,如果你对相关知识不熟悉可以参阅之前的文章。

系列文章目录


前已经写了几篇文章作为本篇的铺垫,如果你对相关知识不熟悉可以参阅之前的文章。


《Java 基础知识之 JDBC》

《数据库事务基础知识》

《如何正确打开 Spring 事务?》


Spring 中的事务传播行为


事务管理并非 Spring 首创,Spring 也借鉴了很多其他的框架,然后加以统一。


在 Spring 中,我们经常使用声明式事务,在方法或类上添加 Spring 的 @Transtional 注解,在这个注解中我们可以指定事务传播行为,这个注解也参考了 EJB 的 javax.ejb.TransactionAttribute 以及 JTA 的 javax.transaction.Transactional,这里先通过对比认识一下这三者的异同。


image.png


从上面的表格中可以看到,在 Spring 的 @Transactional 中都可以找到 EJB、JTA 注解中相应的参数。事实上,Spring 也对 EJB 的 @TransactionAttribute 注解及 JTA 的 @Transactional 加以了支持,在 Spring 中这三个注解都可以使用。


现在将重点转向事务传播行为,上面的三个注解都有事务传播行为,那么这三者的事务传播行为又有何异同呢?


image.png


有没有发现一些问题?Spring 中的事务定义与 EJB、JTA 基本一致,它们名称不仅相同,事实上语义和实现也相似,而且 Spring 还增加了一个 NESTED 类型的事务传播行为。


事务传播行为主要是控制新方法执行时是否使用事务,如何处理线程中以存在的事务。下面是对 Spring 中的这7中事务传播行为的描述。


REQUIRED:默认的事务传播行为;需要事务:存在事务则使用已存在事务,否则创建新的事务;

SUPPORTS:支持已存在事务:存在事务则使用已存在事务,否则以非事务方式运行;

MANDATORY:强制使用事务:存在事务则使用已存在事务,否则抛出异常;

REQUIRES_NEW:需要新事务:存在事务则挂起已存在事务,否则创建新事务;

NOT_SUPPORTED:不支持事务:存在事务则挂起已存在事务,否则以非事务方式运行;

NEVER:从不使用事务:存在事务则抛出异常,否则以非事务方式运行;

NESTED:嵌套事务:存在事务则使创建保存点使用嵌套的事务,否则创建新的事务。


Spring 事务传播行为实现


Spring 事务管理的核心接口是 PlatformTransactionManager,这个接口提供了获取事务、提交事务、回滚事务的方法,子类 AbstractPlatformTransactionManager 提供模板方法,提供了事务管理的主要实现。事务传播行为用于控制事务的获取,因此查看事务获取的相关源码即可了解其实现。


public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
  @Override
  public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
      throws TransactionException {
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    // 获取事务
    Object transaction = doGetTransaction();
    ... 省略日志相关代码
    if (isExistingTransaction(transaction)) {
      // 事务是一个已存在的活动事务,根据事务隔离级别处理事务
      return handleExistingTransaction(def, transaction, debugEnabled);
    }
    ... 省略校验相关代码
    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
      // 不存在事务,抛出异常
      throw new IllegalTransactionStateException(
          "No existing transaction found for transaction marked with propagation 'mandatory'");
    } else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
        def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
        def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
      SuspendedResourcesHolder suspendedResources = suspend(null);
      ... 省略日志相关代码
      try {
        return startTransaction(def, transaction, debugEnabled, suspendedResources);
      } catch (RuntimeException | Error ex) {
        resume(null, suspendedResources);
        throw ex;
      }
    } else {
      ... 省略日志相关代码
      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
    }
  }
}


这段代码先获取事务对象,然后根据事务是否为线程上下文中已存在的事务执行不同的动作。线程上下文中不存在事务的逻辑已经在上面的代码中体现,存在事务的逻辑也类似,与事务传播行为的定义保持一致。我这里画了一张图便于理解。


4.png


总结

Spring 定义了不同的事务传播行为,用于指定获取 TransactionStatus 时的行为,到底使用线程上下文中已有的事务对象,还是创建新的事务对象,还是抛出异常。


Spring 获取的获取事务对象关联着线程上下文中保存的资源对象,对于 JDBC 来说就是 Connection,因此只要获取到 Spring 在线程上下文中保存的资源对象就可以接入 Spring 的事务管理,Spring JDBC、MyBatis 都是这个原理。后续会对 MyBatis 与 Spring 的整合进行分析。


目录
相关文章
|
8月前
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
9月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
1123 1
|
12月前
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
1002 10
|
11月前
|
Java 关系型数据库 MySQL
【Spring】【事务】初学者直呼学会了的Spring事务入门
本文深入解析了Spring事务的核心概念与使用方法。Spring事务是一种数据库事务管理机制,通过确保操作的原子性、一致性、隔离性和持久性(ACID),维护数据完整性。文章详细讲解了声明式事务(@Transactional注解)和编程式事务(TransactionTemplate、PlatformTransactionManager)的区别与用法,并探讨了事务传播行为(如REQUIRED、REQUIRES_NEW等)及隔离级别(如READ_COMMITTED、REPEATABLE_READ)。
754 1
|
XML JSON 前端开发
Spring 面试 7 大问题,你顶得住不?
Spring 面试 7 大问题,你顶得住不?
348 0
Spring 面试 7 大问题,你顶得住不?
|
XML Java 数据格式
Spring 面试问题 TOP 50
Spring Framework 现在几乎已成为 Java Web 开发的标配框架。那么,作为 Java 程序员,你对 Spring 的主要技术点又掌握了多少呢?不妨用本文的问题来检测一下。
1483 0
|
XML Java 数据格式
Spring面试基本问题(1)
1、什么是Spring框架?Spring框架有哪些主要模块? Spring框架是一个为Java应用程序的开发提供了综合、广泛的基础性支持的Java平台。Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。
2107 0
|
10月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1329 0
|
11月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
1150 0
|
7月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
567 4