Spring事务传播机制

简介: 通过举例Spring 父方法、子方法调用以及事务传播机制验证

Spring事务传播类型

本文主要是讲述Spring事务传播机制,也就是大家开发过程中多多少少会遇到的父方法调用子方法,或者A方法调用B方法时事务的传播机制问题,但是在开始讲Spring事务传播机制之前需要先讲一下Spring事务的几种传播类型,如图

image.png

REQUIRED

REQUIRED表示如果当前没有事务,就创建一个事务,如果已经存在一个事务,就加入该事务,是Spring默认的事务传播类型

image.png

也就是说如果外部不存在事务,就开启新的事务,如果外部存在事务,就加入该事务中,如果调用者发生异常,那么调用者和被调用者的事务都回滚。

SUPPORTS

SUPPORTS表示支持当前事务,如果当前没有事务,就以非事务的方式执行,也就是说外部不存在事务,不会开启新事务,外部存在事务时就加入该事务。

MANDATORY

MANDATORY表示支持当前事务,但是跟SUPPORTS不同的是这种事务传播类型具备强制性,当前操作必须存在事务,如果不存在,则抛出异常。

REQUIRES_NEW

REQUIRES_NEW表示如果当前存在事务,则把当前事务挂起,重新创建新的事务并执行,知道新的事务提交或回滚,才会恢复执行原来的事务。这种事务传播类型新创建的事务和被挂起的事务没有任何关系,他们是两个相互独立的事务,外部事务失败后回滚,不会回滚内部事务的执行结果,内部事务执行失败抛出异常,被外部事务捕获时,外部事务可以不处理内部事务的回滚操作。

NOT_SUPPORTED

NOT_SUPPORTED表示以非事务方式执行,如果当前操作在一个事务中,就把当前事务挂起,以非事务方式运行,直到操作完成再恢复事务执行。

NEVER

NEVER表示以非事务的方式执行,如果当前操作存在事务,则抛出异常。

NESTED

NESTED表示如果当前方法有一个事务正在运行,则这个方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务进行提交或回滚,也就是说如果封装事务存在,并且外层事务异常回滚,那么内层事务必须回滚,如果内层事务回滚,不影响外层事务的提交和回滚,当封装事务不存在时,按照REQUIRED事务传播类型执行。

总结

上面7种事务传播类型,日常用到的基本上就REQUIRED、REQUIRES_NEW、NOT_SUPPORTED这几种。

Spring事务举例

现在有这样一种场景,权限管理系统保存角色的时候同时保存角色绑定的菜单,下面开始测试,数据库角色表、角色绑定菜单表 初始数据情况 sys_role、sys_role_menu

image.png


无事务情况

父方法 insertRole保存角色,子方法 insertRoleMenu绑定角色菜单,代码如图

image.png

设置insertRoleMenu 内部发生异常,则insertRole保存角色(普通角色)成功,insertRoleMenu绑定角色菜单失败,验证结果

image.png

父方法未开启事务,子方法开启事务

父方法未开启事务,子方法开启默认事务传播类型REQUIRED,代码如图

image.png

设置insertRoleMenu 内部发生异常,同时insertRoleMenu 开启Spring默认事务,而insertRole未添加事务注解,则insertRole保存角色(普通角色1)成功,insertRoleMenu 绑定角色菜单内部发生异常,事务回滚,验证结果

image.png

父方法开启事务,子方法未开启事务

父方法开启默认事务传播类型,子方法未开启事务,代码如图

image.png

设置insertRoleMenu 内部发生异常,同时insertRole 开启Spring默认事务,而insertRoleMenu未添加事务注解,则insertRoleMenu 内部发生异常,会影响外部insertRole方法的执行,此时均发生回滚,验证结果

image.png

新增(普通角色2)异常回滚,绑定角色菜单异常回滚。

父方法开启事务,子方法开启事务

父方法开启Spring默认事务传播类型,子方法开启Spring默认事务传播类型

image.png

设置insertRoleMenu 内部发生异常,同时insertRole 开启Spring默认事务,insertRoleMenu开启Spring默认事务,则insertRoleMenu 内部发生异常,会影响外部insertRole方法的执行,此时均发生回滚,验证结果

image.png

新增(普通角色3)异常回滚,绑定角色菜单异常回滚。

父方法开启REQUIRED事务,子方法开启NOT_SUPPORTED事务

父方法开启Spring默认事务传播类型,子方法开启NOT_SUPPORTED事务

image.png

设置insertRoleMenu 内部发生异常,同时insertRole 开启Spring默认事务,insertRoleMenu开启Spring NOT_SUPPORTED事务,由于insertRoleMenu将父方法事务挂起,且执行绑定角色菜单之后发生异常,则insertRoleMenu会执行成功,同时由于子方法发生异常,则会影响外部insertRole方法的执行,则insertRole执行失败,事务回滚,验证结果

image.png

新增(普通角色4)增加失败,绑定角色菜单执行成功。

父方法开启REQUIRED事务,子方法开启REQUIRES_NEW事务

父方法开启Spring默认事务传播类型,子方法开启Spring REQUIRES_NEW事务传播类型

image.png

设置insertRoleMenu 内部发生异常,同时insertRole 开启Spring默认事务,insertRoleMenu开启Spring REQUIRES_NEW事务,此时insertRoleMenu发生异常时,则insertRoleMenu、insertRole均会执行失败,事务回滚,验证结果

image.png

新增(普通角色5)增加失败,绑定角色菜单执行失败,事务回滚。

父方法开启REQUIRED事务,子方法开启REQUIRES_NEW事务

父方法开启Spring默认事务传播类型,子方法开启Spring REQUIRES_NEW事务传播类型,与上一种不同的是,异常产生发生在父方法最后一行

image.png

设置insertRole 内部发生异常,且异常发生在最后一行,同时insertRole 开启Spring默认事务,insertRoleMenu开启Spring REQUIRES_NEW事务,此时insertRole发生异常时,则insertRole均会执行失败,事务回滚,insertRoleMenu执行成功,验证结果

image.png

新增(普通角色6)增加失败,绑定角色菜单执行成功。

父方法开启REQUIRED事务,子方法开启REQUIRES_NEW事务

父方法开启Spring默认事务传播类型,子方法开启Spring REQUIRES_NEW事务传播类型,异常产生发生在父方法最后一行,同时父方法、子方法是在同一个类中的内部调用

image.png

设置insertRole 内部发生异常,且异常发生在最后一行,同时insertRole 开启Spring默认事务,insertRoleMenu开启Spring REQUIRES_NEW事务,此时insertRole发生异常时,则insertRole、insertRoleMenu执行失败,事务回滚,验证结果

image.png

新增(普通角色7)增加失败,绑定角色菜单执行失败。

Spring 事务失效场景

数据库不支持事务

Spring事务生效的前提是连接的数据库存储引擎支持事务,比如Mysql 的MyISAM存储引擎不支持事务,则Spring事务会失效。

事务方法未被Spring管理

如果事务所在的类没有被交给Spring 管理,或者说没有加载到Spring IOC容器中,则该类方法上的事务会失效,比如

image.png

如果没有@Service注解,则该类下的方法上的事务会失效。

事务方法私有private

如果事务注解的方法为内部的私有private方法,则事务会失效。

同一个类中的方法调用

同一个类中的父方法调用子方法,都开启了事务,如图

image.png

子方法的事务会失效

不正确的异常捕获

如果发生异常的代码被try catch捕获,则Spring 管理器无法感知到异常,导致事务失效。

错误的异常类型

Spring 事务默认的捕获的异常是RuntimeException,如果代码中执行失败抛出了Exception异常,则事务会失效


总结

以上内容基于日常工作及学习,仅供参考,有兴趣的同学也可以买一本《深入理解分布式事务 原理与实战》,读之受益良多。


相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
3天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
37 14
|
17天前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
40 2
Spring高手之路26——全方位掌握事务监听器
|
19天前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
20天前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
35 4
|
25天前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
52 8
|
1月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
52 1
Spring高手之路24——事务类型及传播行为实战指南
|
23天前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
1月前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
47 3
|
3月前
|
Java 数据库连接 数据库
spring复习05,spring整合mybatis,声明式事务
这篇文章详细介绍了如何在Spring框架中整合MyBatis以及如何配置声明式事务。主要内容包括:在Maven项目中添加依赖、创建实体类和Mapper接口、配置MyBatis核心配置文件和映射文件、配置数据源、创建sqlSessionFactory和sqlSessionTemplate、实现Mapper接口、配置声明式事务以及测试使用。此外,还解释了声明式事务的传播行为、隔离级别、只读提示和事务超时期间等概念。
spring复习05,spring整合mybatis,声明式事务
下一篇
DataWorks