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语言中的面向对象特性总结

    【课前思考】1.什么是对象?什么是类?什么是包?什么是接口?什么是内部类?2.面向对象编程的特性有哪三个?它们各自又有哪些特性?3.你知道java语言在面向对象编程方面有何独特的特点吗?&

    2021年12月27日
    40
  • Hbase面试题总结(大数据面试)

    Hbase面试题总结(大数据面试)概述

    2022年5月6日
    55
  • linux关闭防火墙命令_防火墙配置策略

    linux关闭防火墙命令_防火墙配置策略在外部访问CentOS中部署应用时,需要关闭防火墙。关闭防火墙命令:systemctlstopfirewalld.service开启防火墙:systemctlstartfirewalld.service关闭开机自启动:systemctldisablefirewalld.service开启开机启动:systemctlenablefirewalld.service…

    2025年9月21日
    11
  • 51单片机入门教程(5)——定时器中断

    51单片机入门教程(5)——定时器中断51 单片机入门教程 5 定时器中断一 中断的概念二 定时器中断 2 1 软件延时的不足 2 2 中断寄存器 2 2 1 中断允许控制寄存器 IE2 2 2 定时器工作方式寄存器 TMOD2 2 3 定时器控制寄存器 TCON2 2 4 定时器初值寄存器 THx TLx2 3 定时器中断程序写法写在开头 中断是包括单片机在内的所有微处理器很重要的功能之一 初学单片机必须这一部分的知识 一 中断的概

    2025年11月17日
    3
  • 实用工具系列 – Xshell安装下载与使用「建议收藏」

    实用工具系列 – Xshell安装下载与使用「建议收藏」一、介绍二、下载三、安装四、使用

    2025年10月17日
    6
  • UC浏览器如何开启html5,如何开启手机uc浏览器中的极速模式

    UC浏览器如何开启html5,如何开启手机uc浏览器中的极速模式如何开启手机 uc 浏览器中的极速模式当我们在使用手机的时候 可以下载 uc 浏览器来浏览网页 为了提升网页的浏览速度 可以开启浏览器中的极速模式 接下来就由小编来告诉大家如何操作 具体如下 1 第一步 打开手机并在桌面找到 uc 浏览器图标 点击进入 2 第二步 进入 app 主页后 点击下方的三横主菜单按钮 3 第三步 在弹出的菜单中找到设置选项 点击进入 4 第四步 跳转至更多设置页面后 点击下方的极速 省

    2025年7月10日
    5

发表回复

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

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