Spring常用事务传播特性

Posted 爱叨叨的程序狗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring常用事务传播特性相关的知识,希望对你有一定的参考价值。

前提

以下案例使用成功的前提是Spring事务传播机制正常工作的情况下。
个人理解Spring传播机制一定要自己写Demo测试复现以方便理解记忆,避免在企业项目开发中踩坑。
博客错误及不足之处欢迎评论指正,谢谢!

Propagation.REQUIRED

默认事务,如果不存在事务,创建一个事务,然后执行事务操作,最常见的选择。

该事务的行为:

  1. 如果它作为一个子事务方法,在其他事务方法中被调用,那么该方法不会创建新的事务,加入当前事务,使用现有的父级别的事务。
  2. 如果它作为一个子事务方法,没有在其他事务方法中被调用,而是在非事务方法中直接调用,那么它会创建一个新的事务来执行数据库操作。

应用场景:

不知道方法的调用者是否创建了事务,但是要求当前被调用的方法必须在一个事务中执行。

注意:当需要日志记录的业务场景中,外部事务记录日志信息留痕,并在外部代码中捕获异常处理,主流业务使用单独方法,传播行为REQUIRES_NEW,可以保证在不关注主流业务的情况下日志被留痕。

Propagation.REQUIRES_NEW

新建事务,不依赖于环境的”内部“事务,这个事务将被完全提交回滚而不依赖于外部事务,它拥有自己的隔离范围,自己的锁,当内部事务开始执行时,外部事务将被挂起,内部事务结束时,外部事务将继续执行。

应用场景:

常用于日志记录或交易失败仍要留痕及时序控制,即事务步骤要求时序的情况。

public boolean createUser(User user) 
    userMapper.insertUser(user);
    Menu menu = new Menu();
    menu.setId(99);
    menu.setPattern("11");
    menuService.insertMenuRequireNew(menu);
    return true;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertMenuRequireNew(Menu menu) 
    menuMapper.addMenu(menu);
    if (true) 
        throw new RuntimeException();
    

  1. 内部事务异常,外部事务未捕获Service异常时,内部Service异常时,不影响外部事务,仅回滚内部事务。

  2. 内部事务异常,外部事务捕获Service异常时,内部Service异常时,影响内部事务,两事务均回滚。

  3. 外部事务异常,在调用内部事务前,外部事务Service抛出异常,外部事务回滚

Propagation.NESTED

Spring查询当前是否存在事务,如果已存在事务,创建一个保存点,即若代码逻辑抛出异常,代码回滚到保存点,如果没有活跃的事务,则作用和默认REQUIRED类型事务一致。

NESTED类型创建的事务,实则为字事务。

异常类型Service 1Service 2
user正常/menu正常正常提交正常提交
user异常/menu正常回滚未执行
user正常/menu异常外部user调用menu时使用try/catch捕获,user正常提交。当外部user调用menu不使用try/catch捕获时,user、menu均回滚回滚
user异常/menu异常回滚回滚
Service 1
@Transactional(propagation = Propagation.REQUIRED)
public void createUserNestedOpen() 
    try 
        User user = new User(221, "NESTED");
        userMapper.insertUser(user);
        Menu menu = new Menu();
        menu.setId(99);
        menu.setPattern("11");
        menuService.insertMenu(menu);
     catch (Exception e) 
        log.error(e.getMessage());
    

Service 2
@Transactional(propagation = Propagation.NESTED)
public void insertMenu(Menu menu) 
    menuMapper.addMenu(menu);
    if (true) 
        throw new RuntimeException();
    

使用try/catch捕获内部事务的情况

可见事务id是同一个。

外部事务异常

以上是关于Spring常用事务传播特性的主要内容,如果未能解决你的问题,请参考以下文章

spring事务的传播特性

spring事务的传播特性

Spring 事务传播特性

Spring事务隔离级别和传播特性

Spring事务的传播特性和隔离级别

Spring事务隔离级别和传播特性