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


目录
相关文章
|
2月前
|
SQL Java 关系型数据库
【SpringFramework】Spring事务
本文简述Spring中数据库及事务相关衍伸知识点。
51 9
|
3月前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
156 13
|
3月前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
93 2
Spring高手之路26——全方位掌握事务监听器
|
3月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
7月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
4月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
4月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
4月前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
111 4
|
5月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
176 2
|
5月前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
60 0

热门文章

最新文章