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


相关推荐

  • Nginx使用

    Nginx使用

    2021年7月10日
    73
  • IDEA2022激活码mac【2022最新】2022.03.08

    (IDEA2022激活码mac)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年4月2日
    174
  • 谈谈数据库连接池的原理及应用_常用的数据库连接池

    谈谈数据库连接池的原理及应用_常用的数据库连接池这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包。

    2025年12月15日
    3
  • 计算机科学与技术现状分析_信息科学与计算机科学的区别

    计算机科学与技术现状分析_信息科学与计算机科学的区别摘要:在这个科技突飞猛进发展的时代,计算机网络已经家喻户晓,在日常生活中也起着不可忽视的作用,计算机的发展提高了人们的生活质量,加快了信息的传播,现如今,各个国家都比较重视计算机科学与技术的发展,使计算机科学与技术在全国综合国力竞争的作用逐渐加大。对于这种情况,加快计算机科学与技术的发展,不但有利于人们更快捷地了解如今的发展趋势和历史,且还推动计算机科学与技术的进步,方便人们的生活。本文首先阐述了…

    2022年10月20日
    2
  • 网页大作业代码自取[通俗易懂]

    网页大作业代码自取[通俗易懂]网页大作业(内有代码可免费自取) 为了便于大家自取,代码都写在一页上,本人还是建议大家通过外链样式来引入css,代码仅供学习,如有侵权联系删除。![主页效果展示](https://img-blog.csdnimg.cn/20210505002015238.jpeg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpb25nbGxpbmc=,size_1

    2022年9月24日
    2
  • 环信-(php)服务器端REST API

    环信-(php)服务器端REST API

    2021年11月9日
    42

发表回复

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

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