spring事务的传播机制

spring事务的传播机制什么是事务 数据库事务是指一系列严密操作 要么全部成功 要么全部失败 它有四种特性 原子性 一致性 隔离性和持久性 而 spring 事务是封装在数据库事务之上的一种事务处理机制 它有两种管理方式 编程式事务和声明式事务 在平时使用中 我们大多使用 Transactiona 声明式事务来管理 这也是 spring 推荐的方式 下面例子也统一采用此种方式 下面我们主要来看看 spring 事务的传播机制 spring 事务的传播机制 spring 事务的传播机制有七种 REQUIRED REQUIRES NEW NES

什么是事务?

数据库事务是指一系列严密操作,要么全部成功,要么全部失败。它有四种特性:原子性、一致性、隔离性和持久性

而spring事务是封装在数据库事务之上的一种事务处理机制,它有两种管理方式:编程式事务和声明式事务。在平时使用中,我们大多使用@Transactional声明式事务来管理,这也是spring推荐的方式,下面例子也统一采用此种方式。

下面我们主要来看看spring事务的传播机制

spring事务的传播机制

spring事务的传播机制有七种:REQUIRED、REQUIRES_NEW、NESTED、SUPPORTS、NOT_SUPPORTED、MANDATORY和NEVER

首先要知道事务的传播指的是一个方法调用另外一个方法并将事务传递给它,而传播机制是针对被调用者,控制它是否被传播或者被怎样传播。注:后面多次提到 此方法在/不在事务中,指的是调用者是否开启了事务

下面我们来仔细分析一下这几种传播方式。

REQUIRED(有事务则加入,没有则创建)

REQUIRED是spring事务的默认方式,如果当前方法不在事务中,就创建一个新的事务;如果当前方法在事务中,就加入到这个事务中。

举个例子,我们操作book书籍表和title章节表,先插入book表,然后再插入title表(下面几种传播方式都以这两张表为例)。BookServiceImpl中方法(调用者)调用TitleServiceImpl中方法(被调用者)。下面分两种情况:

1、调用者有事务

@Slf4j @Service @AllArgsConstructor public class BookServiceImpl implements BookService { 
    private final BookMapper bookMapper; private final TitleService titleService; @Override @Transactional public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //传播事务 titleService.titleTransaction(); } } @Slf4j @Service @AllArgsConstructor public class TitleServiceImpl implements TitleService { 
    private final TitleMapper titleMapper; @Override @Transactional(propagation = Propagation.REQUIRED) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); } } // 输出,被调用者使用的是调用者的事务 调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest 被调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest 

2、调用者无事务

//BookServiceImpl类 @Override public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //传播事务 titleService.titleTransaction(); } //TitleServiceImpl类 @Override @Transactional(propagation = Propagation.REQUIRED) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); } // 输出,被调用者创建新事务 调用者中事务:null 被调用者中事务:com.example.demo.transaction.service.impl.TitleServiceImpl.requiredTest 

REQUIRES_NEW(新事务,有事务就创建新事务)

如果当前方法存在事务,则把当前事务挂起,(这个挂起怎么理解呢?就是将现存的事务放在一边,我不用这个事务),自己新建一个事务。调用者事务和被调用者事务两不相干。

//BookServiceImpl类 @Override @Transactional public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //传播事务 titleService.titleTransaction(); } //TitleServiceImpl类 @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); } // 输出,被调用者和调用者是两个不同事务 调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest 被调用者中事务:com.example.demo.transaction.service.impl.TitleServiceImpl.requiredTest 

NESTED(嵌套事务,有事务就创建子事务)

如果当前方法存在事务,则创建一个子事务,等父事务提交以后,子事务再提交;如果当前没有事务,则新建事务。(子事务异常,父事务不一定回滚;但父事务异常,则子事务肯定回滚)

1、子事务异常

//BookServiceImpl类 @Override @Transactional public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); try { 
    // 传播事务,捕获异常 titleService.titleTransaction(); } catch (Exception e) { 
    e.printStackTrace(); } } //TitleServiceImpl类 @Override @Transactional(propagation = Propagation.NESTED) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); throw new RuntimeException("子事务异常"); } // 输出,title表插入回滚了,但是book表插入未回滚 调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest 被调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest java.lang.RuntimeException: 子事务异常 

2、父事务异常

//BookServiceImpl类 @Override @Transactional public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //传播事务 titleService.titleTransaction(); throw new RuntimeException("父事务异常"); } //TitleServiceImpl类 @Override @Transactional(propagation = Propagation.NESTED) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); } // 输出,book的插入和title的插入都回滚了 调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest 被调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest java.lang.RuntimeException: 父事务异常 

SUPPORTS(支持事务,有没有都可以)

如果当前方法存在事务,则加入事务;如果当前方法不存在事务,则以非事务方式运行。这个传播行为和不写没多大区别,以后有这需求,可以不用写@Transactional。

代码:略

NOT_SUPPORTED(不支持事务,有事务也是以非事务方式执行)

这个传播行为就是,不管咋地都传不到我身上,我就是一直以非事务方式执行。

//BookServiceImpl类 @Override @Transactional public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //传播事务 titleService.titleTransaction(); } //TitleServiceImpl类 @Override @Transactional(propagation = Propagation.NOT_SUPPORTED) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); throw new RuntimeException("异常"); } // 输出,虽然被调用者中有事务,也抛出异常,但是数据不会回滚 调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest 被调用者中事务:com.example.demo.transaction.service.impl.TitleServiceImpl.requiredTest java.lang.RuntimeException: 异常 

MANDATORY(必须有事务,没有就抛异常)

这个传播行为就是不管咋地我都要在事务中,如果当前方法在事务中,就加入当前事务中;如果当前方法不在事务中,就抛异常。

1、当前方法存在事务

//BookServiceImpl类 @Override @Transactional public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //传播事务 titleService.titleTransaction(); } //TitleServiceImpl类 @Override @Transactional(propagation = Propagation.MANDATORY) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); } // 输出,被调用者加入到当前事务中 调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest 被调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest 

2、当前方法不存在事务

//BookServiceImpl类 @Override public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //传播事务 titleService.titleTransaction(); } //TitleServiceImpl类 @Override @Transactional(propagation = Propagation.MANDATORY) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); } // 输出,无事务则抛异常 调用者中事务:null org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory' 

NEVER(不可能有事务,有事务就抛异常)

此传播方式就是不管咋地,谁调用我,你就不许有事务,否则我就抛异常。

1、调用者有事务

//BookServiceImpl类 @Override @Transactional public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //传播事务 titleService.titleTransaction(); } //TitleServiceImpl类 @Override @Transactional(propagation = Propagation.NEVER) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); } // 输出,调用者有事务,则被调用者就抛异常 调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never' 

2、调用者无事务

//BookServiceImpl类 @Override public void bookTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //传播事务 titleService.titleTransaction(); } //TitleServiceImpl类 @Override @Transactional(propagation = Propagation.NEVER) public void titleTransaction() { 
    String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); } // 输出,调用者无事务,被调用者虽然有事务,但是会以无事务方式执行 调用者中事务:null 被调用者中事务:com.example.demo.transaction.service.impl.TitleServiceImpl.requiredTest 

总结

接下来我们总结一下各种传播方式下,调用者和被调用者是怎么操作事务的。注:A方法是调用者,B方法是被调用者。对于A方法来说,就两种情况:有事务和无事务,而对于B方法来说,有七种情况,下面看看每种情况下B方法是怎样操作事务的。

A方法调用B方法,B方法定义的事务类型 A方法有事务时 A方法无事务时
REQUIRED:默认 B和A事务合并成一个事务 B新建一个事务
REQUIRES_NEW:必须新的 B新建一个事务,和A事务无关,互不影响 B新建一个事务
NESTED:嵌套 B新建一个A的子事务,A异常影响B,B异常不影响A B新建一个事务
SUPPORTS:支持 B加入到A事务中 B无事务
NOT_SUPPORTED:不支持 挂起A事务,B以无事务方式执行 B无事务
MANDATORY:强制 B加入到A事务中 B抛异常
NEVER:绝不 B抛异常 B无事务


扫一扫,关注我

spring事务的传播机制

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233994.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 《畅玩NAS》家庭 NAS 服务器搭建方案「建议收藏」

    《畅玩NAS》家庭 NAS 服务器搭建方案「建议收藏」NAS(NetworkAttachedStorage:网络附属存储)按字面简单说就是连接在网络上,具备资料存储功能的装置,因此也称为“网络存储器”。它是一种专用数据存储服务器。它以数据为中心,将存储设备与服务器彻底分离,集中管理数据,从而释放带宽、提高性能、降低总拥有成本、保护投资。其成本远远低于使用服务器存储,而效率却远远高于后者。目前国际著名的NAS企业有Netapp、EMC、OUO等。说白话,就是家用的服务器。首选谈谈家庭NAS服务器的基本需求:1.7*24小时运行,最好有UPS电源保护

    2022年6月22日
    78
  • vbnet程序设计教程_vb程序设计入门教程

    vbnet程序设计教程_vb程序设计入门教程链接:https://pan.baidu.com/s/1NzPq4rdwhJEDeHhDDl6wIQ提取码:3nz3复制这段内容后打开百度网盘手机App,操作更方便哦微信扫一扫即可获取文件

    2022年9月28日
    2
  • linux修改用户密码命令_linux更改用户密码的命令

    linux修改用户密码命令_linux更改用户密码的命令Linux修改用户密码使用的Linux版本是:ubuntu-18.10-live-server-amd64知道一个用户名密码时,修改用户密码,各个版本下都是通用的;重置密码的时候,版本不同,可能操作的地方不一样了。如果一个账号的密码都不记得了(这通常是需要修改用户密码最多的情况),那就需要重置密码,相对就比较复杂一些,放在最后讲。但凡知道一个用户的密码,那就好办。(普通用户登录的情况下,也可以修改root用户的密码。)1.知道一个账号的密码这就是正常情况下,修改用户密码。1.1知道roo

    2022年9月6日
    6
  • idea 添加Tomcat_懂车帝怎么添加

    idea 添加Tomcat_懂车帝怎么添加使用IDEA编辑器开发项目十分便捷,这里介绍使用IDEA编辑器添加Tomcat1、新建web工程这里有一个已经创建好的web项目2、配置tomcat配置tomcat前,先确保本地已经下载并安装完成了tomcat如果不清楚如何安装tomcat,请参考:安装tomcat点击Run,EditConfigurations…点击+号,添加服务配置找到TomcatServer,选择Local自定义Name,这里是T…

    2022年10月17日
    3
  • Java程序员面试简历模板(30套简历模板+300套简历)「建议收藏」

    Java程序员面试简历模板(30套简历模板+300套简历)「建议收藏」简历是吸引面试官的第一步,找工作就从包装简历开始

    2022年7月9日
    128
  • 为何asp.net2.0中 rendercontrol 对于有些服务器端的控件会不支持[通俗易懂]

    为何asp.net2.0中 rendercontrol 对于有些服务器端的控件会不支持[通俗易懂]比如报出rendercontrol必须放在具有runat=server这样的错误原因:http://topic.csdn.net/t/20051207/21/4444706.html解决方法:http://www.cnblogs.com/zhangronghua/archive/2008/11/07/951899.html

    2022年7月20日
    20

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号