那些年面试官问过我的 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 的整合进行分析。


目录
相关文章
|
1月前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
1月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
6天前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
6天前
|
缓存 Java 数据库
【Java面试题汇总】Spring篇(2023版)
IoC、DI、aop、事务、为什么不建议@Transactional、事务传播级别、@Autowired和@Resource注解的区别、BeanFactory和FactoryBean的区别、Bean的作用域,以及默认的作用域、Bean的生命周期、循环依赖、三级缓存、
【Java面试题汇总】Spring篇(2023版)
|
1月前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
1月前
|
存储 缓存 Java
复盘女朋友面试4个月的Spring面试题
该文章复盘了关于 Spring 的面试题,包括 Spring 的好处、Bean 的生命周期、Spring 循环依赖的解决方法、AOP 的原理以及 Spring Boot 自动装配的原理等,强调对 Spring 核心原理的清晰理解对于回答面试题的重要性。
复盘女朋友面试4个月的Spring面试题
|
1月前
|
前端开发 Java 数据库连接
一天十道Java面试题----第五天(spring的事务传播机制------>mybatis的优缺点)
这篇文章总结了Java面试中的十个问题,包括Spring事务传播机制、Spring事务失效条件、Bean自动装配方式、Spring、Spring MVC和Spring Boot的区别、Spring MVC的工作流程和主要组件、Spring Boot的自动配置原理和Starter概念、嵌入式服务器的使用原因,以及MyBatis的优缺点。
|
1月前
|
算法 关系型数据库 MySQL
一天五道Java面试题----第七天(mysql索引结构,各自的优劣--------->事务的基本特性和隔离级别)
这篇文章是关于MySQL的面试题总结,包括索引结构的优劣、索引设计原则、MySQL锁的类型、执行计划的解读以及事务的基本特性和隔离级别。
|
30天前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
2月前
|
Java 测试技术 数据库
Spring Boot中的项目属性配置
本节课主要讲解了 Spring Boot 中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。最后介绍了开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。