【Spring】一文搞懂Spring事务传播机制

在这里插入图片描述

介绍:

Spring事务是应用程序处理中非常重要的一部分,它可以保证数据库操作的一致性和可靠性,提高系统的稳定性和性能。事务传播机制是Spring事务管理中的一个核心概念,它定义了在一个方法调用过程中,事务的开始和结束时间以及数据源的绑定方式。本文将会介绍Spring事务传播机制的基本概念和常见的传播机制类型。

Spring的事务,符合ACID标准,也具有标准的事务隔离级别。

事务的传播机制

七种传播机制

  1. PROPAGATION_REQUIRED: 这是默认的事务传播行为。如果在当前方法调用时存在一个活动事务,那么它会加入到这个事务中。如果没有活动事务,将会启动一个新的事务。
  2. PROPAGATION_SUPPORTS: 该传播行为表示如果存在一个活动事务,则加入该事务。如果没有活动事务,则无须非事务执行。它没有明确的事务边界,因此慎用此传播行为。
  3. PROPAGATION_MANDATORY: 这个传播行为表示如果存在一个活动事务,则加入该事务。但如果没有活动事务,则抛出异常。
  4. PROPAGATION_REQUIRES_NEW: 这个传播行为始终会启动一个新事务。如果存在一个活动的事务,它会被挂起,直到新事务执行完毕。
  5. PROPAGATION_NOT_SUPPORTED: 该传播行为表示总是非事务执行。如果存在一个活动的事务,它将被挂起,直到非事务执行完毕。
  6. PROPAGATION_NEVER: 这个传播行为表示必须在非事务环境下运行。如果存在一个活动的事务,则抛出异常。
  7. PROPAGATION_NESTED: 此传播行为表示如果存在一个活动事务,则以嵌套事务的方式运行。如果没有活动事务,将会启动一个新的事务。嵌套事务意味着如果内层事务失败,则可以回滚到最近的保存点(savepoint),但外层事务不会受影响。需要注意的是,可能不是所有的数据库都支持嵌套事务,同时如果使用嵌套事务,数据库的JDBC驱动应支持 java.sql.Savepoint。
可以按支持当前事务与否分成三类。
在这里插入图片描述

事务传播机制处理演示:

首先,我们创建一个User实体和对应的UserMapper:

// User.java
public class User {
    private Long id;
    private String name;
    private Integer age;
    // getter和setter...
}

// UserMapper.java
public interface UserMapper extends BaseMapper<User> {
}

这里提供一个简单的示例,演示使用 Spring 和 MyBatis Plus 实现七种事务传播机制,并模拟抛出异常观察各传播机制在发生错误时的处理结果。

首先,我们需要创建一个模拟错误的方法:

public void createError() {
    throw new RuntimeException("模拟抛出错误!");
}

然后,在 UserService 中的每个示例方法中调用 createError() 方法。

事务传播机制及错误处理结果如下:

  1. PROPAGATION_REQUIRED:
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequired() {
    insertUser("张三", 20);
    createError();  // 模拟抛出错误
    insertUser("李四", 25);
}

处理结果:张三插入失败,回滚事务。因为 propagateRequired() 方法自身在一个事务中运行,当内部产生异常时,整个事务将回滚。

  1. PROPAGATION_SUPPORTS:
@Transactional(propagation = Propagation.SUPPORTS)
public void propagationSupports() {
    insertUser("王五", 30);
    createError();  // 模拟抛出错误
    insertUser("赵六", 35);
}

处理结果:如果调用方法的上级方法有事务,那么王五插入失败,回滚事务。如果上级方法没有事务,王五插入成功,赵六插入失败,因为不会影响任何事务。

  1. PROPAGATION_MANDATORY:
@Transactional(propagation = Propagation.MANDATORY)
public void propagationMandatory() {
    insertUser("孙七", 40);
    createError();  // 模拟抛出错误
    insertUser("周八", 45);
}

处理结果:孙七插入失败,回滚事务。该方法要求上级方法必须存在事务,否则将抛出异常。当内部产生异常时,整个事务将回滚。

  1. PROPAGATION_REQUIRES_NEW:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void propagationRequiresNew() {
    insertUser("吴九", 50);
    createError();  // 模拟抛出错误
    insertUser("郑十", 55);
}

处理结果:吴九插入成功,因为该方法总是运行在一个新的事务中,和外部事务无关,抛出异常仅回滚新增的用户郑十。

  1. PROPAGATION_NOT_SUPPORTED:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void propagationNotSupported() {
    insertUser("陈十一", 60);
    createError();  // 模拟抛出错误
    insertUser("杨十二", 65);
}

处理结果:陈十一插入成功,杨十二插入失败。该方法运行在无事务环境下,所以陈十一成功插入。抛出异常后,不会影响陈十一的记录。

  1. PROPAGATION_NEVER:
@Transactional(propagation = Propagation.NEVER)
public void propagationNever() {
    insertUser("张十三", 70);
    createError();  // 模拟抛出错误
    insertUser("李十四", 75);
}

处理结果:张十三插入成功。该方法要求上层方法不能存在事务,否则抛出异常。异常发生后,不会影响张十三的记录。

  1. PROPAGATION_NESTED:
@Transactional(propagation = Propagation.NESTED)
public void propagationNested() {
    insertUser("王十五", 80);
    createError();  // 模拟抛出错误
    insertUser("赵十六", 85);
}

处理结果:王十五插入失败,回滚事务。该方法如果上级方法有事务,则运行在一个嵌套事务中。当内部产生异常时,只会回滚到该事务的保存点。

事务在什么情况下会失效

在使用 Spring 的默认传播机制(Propagation.REQUIRED 时,事务可能在以下情况下失效:
一:未正确使用代理:

  下方三个问题本质都是没有正确使用aop代码,spring事务时根据代理来进行传递的,使用事务时务必正确使用代理获取bean。

  1. @Transactional 注解不能应用于 privatefinalstatic 方法。这些方法类型上不能创建代理时,事务将不起作用。

  2. 方法内部调用:在一个类中,事务方法的调用是通过方法内部调用的,而没有通过代理对象调用。例如,一个非事务方法调用了一个事务方法,但都在同一个类中,事务将失效。

    同类方法调用时,不能直接使用this调用。

  正确示例:
在这里插入图片描述
3. Proxying Mechanism:如果调用的方法不是由代理对象调用,那么事务会失效。请确保正确使用代理对象。
>检查当前service类是否是通过spring bean加载的。

二:异常类型不匹配:

  1. 如果方法抛出的异常与事务配置中定义的回滚类型不匹配,事务可能失效。默认情况下,事务会回滚所有运行时异常(RuntimeException 及其子类)。可以通过 @TransactionalrollbackFornoRollbackFor 属性自定义异常类型。

请注意,这里只列出了默认传播机制情况下的失效场景。根据具体的应用需求和代码组织,失效的原因可能会有所不同。在遇到事务失效的问题时,请根据具体情况检查代码和配置,确保遵循正确的设计和实践。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小王笃定前行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值