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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 阿里巴巴Java开发手册(终极版)[通俗易懂]

    不知不觉间,2020年已经过了一大半了,作为技术圈中你,准备好迎接最新的变化了吗?在本文中,我们将以编程界最常用的编程语言Java为例,分享最为主流的技术与工具。2020年最流行的Java开发技术Java几乎无处不在,无论在智能手机、台式机、游戏设备还是科学超级计算机上,处处都有Java的影子。全世界有数百万的Java程序员在开发基于Java的产品。然而,如此激烈的竞争,意味着Java开发人员必须时刻保持领先地位。为此,他们必须随时了解和洞悉Java生态系统中的最新动..

    2022年4月18日
    51
  • mysql 练习题

    mysql 练习题一、上机内容使用SQL语句创建数据库studentsdb。、Createdatabasestudentdb;2.使用SQL语句选择studentsdb为当前使用数据库。Usestudentdb;3.使用SQL语句在studentsdb数据库创建数据表student_info、curriculum、grade,三个表的数据结构如表1-表3所示。createtablestude…

    2022年9月18日
    0
  • 将后台返回字符串数据转为jquery对象,并做一些操作

    将后台返回字符串数据转为jquery对象,并做一些操作

    2021年8月31日
    52
  • 卓越性能 の 军火库「建议收藏」

    卓越性能 の 军火库「建议收藏」在介绍性能优化的军火库之前,先来扯几句题外话。希望这些题外话,能打消你追求卓越性能的理想,来甘心当一枚圆滑的钉子。我是非常不推荐程序员,对公司的业务,进行性能优化的。说这话,纯粹是基于个人自身安全考虑。因为性能优化,在大多数公司,属于费力不讨好的工作项。追求极简的代码,性能卓越的代码,是有追求的程序员的目标。但随着经历了大大小小的公司,我发现很多优秀的程序员,在经受着这种追求的反嗜,以至于痛不欲生。下有下面几点原因,虽然我们知道它肯定是错的,但我们无能无力:公司按照完成的功能,对程序员…

    2022年9月30日
    0
  • 141. 环形链表(链表)

    141. 环形链表(链表)给定一个链表,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。如果链表中存在环,则返回 true 。 否则,返回 false 。进阶:你能用 O(1)(即,常量)内存解决此问题吗?示例 1:输入:head = [3,2,0,-4],

    2022年8月9日
    2
  • ThinkPHP中_after_update、_before_update等的用法

    ThinkPHP中_after_update、_before_update等的用法

    2021年10月28日
    34

发表回复

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

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