前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring常用事务传播特性

Spring常用事务传播特性

作者头像
关忆北.
发布2022-10-27 15:12:08
1510
发布2022-10-27 15:12:08
举报
文章被收录于专栏:关忆北.关忆北.
前提

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

Propagation.REQUIRED

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

该事务的行为:

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

应用场景:

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

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

Propagation.REQUIRES_NEW

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

应用场景:

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

代码语言:javascript
复制
public boolean createUser(User user) {
    userMapper.insertUser(user);
    Menu menu = new Menu();
    menu.setId(99);
    menu.setPattern("11");
    menuService.insertMenuRequireNew(menu);
    return true;
}
代码语言:javascript
复制
@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 1

Service 2

user正常/menu正常

正常提交

正常提交

user异常/menu正常

回滚

未执行

user正常/menu异常

外部user调用menu时使用try/catch捕获,user正常提交。当外部user调用menu不使用try/catch捕获时,user、menu均回滚

回滚

user异常/menu异常

回滚

回滚

代码语言:javascript
复制
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());
    }
}
代码语言:javascript
复制
Service 2
@Transactional(propagation = Propagation.NESTED)
public void insertMenu(Menu menu) {
    menuMapper.addMenu(menu);
    if (true) {
        throw new RuntimeException();
    }
}
使用try/catch捕获内部事务的情况

可见事务id是同一个。

NESTED异常
NESTED异常
外部事务异常
外部事务异常
外部事务异常
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前提
  • Propagation.REQUIRED
  • Propagation.REQUIRES_NEW
  • Propagation.NESTED
    • 使用try/catch捕获内部事务的情况
      • 外部事务异常
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档