目录

1、属性介绍

2、传播机制

  • 准备例子

  • 总结

3、原理


4、失效场景

一、属性介绍

1、isolation 属性

事务的隔离级别,默认值为 Isolation.DEFAULT。可选的值有:

  • Isolation.DEFAULT:使用底层数据库默认的隔离级别

  • Isolation.READ_UNCOMMITTED:读取未提交数据(会出现脏读,不可重复读、幻读)基本不使用

  • Isolation.READ_COMMITTED:读取已提交数据(会出现不可重复读和幻读)

  • Isolation.REPEATABLE_READ:可重复读(会出现幻读)

  • Isolation.SERIALIZABLE:串行化

2、timeout 属性

事务的超时时间,默认值为 -1。如果超过该时间限制但事务还没有完成,则自动回滚事务

3、readOnly 属性

指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true

4、rollbackFor 属性

用于指定能够触发事务回滚的异常类型,可以指定多个异常类型

5、noRollbackFor 属性

抛出指定的异常类型,不会滚事务,也可以指定多个异常类型

7、propagation 属性

事务的传播行为,默认值为 Propagation.REQUIRED。可选的值有:

  • PROPAGATION.REQUIRED:如果当前没有事务,则创建一个新事务。如果当前存在事务,就加入该事务。该设置是最常用的设置

  • PROPAGATION.SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务。如果当前不存在事务,就以非事务执行

  • PROPAGATION.MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常

  • PROPAGATION.REQUIRE_NEW:创建新事务,无论当前存不存在事务,都创建新事务

  • PROPAGATION.NOT_SUPPORTED:以非事务方式执行操作,如果当前事务存在,就把当前事务挂起

  • PROPAGATION.NEVER:以非事务方式执行,如果当前存在事务,则抛出异常

  • PROPAGATION.NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按 REQUIRED 属性执行

二、传播机制

属性上最值得关注的应该就是传播行为了,而在其中最难理解的就是这三个了,毕竟我们最关注的就是两个方法相互调用,发生了异常,是怎么回滚的是吧?其他的4个相对来说比较好理解

  • PROPAGATION.REQUIRED

  • PROPAGATION.REQUIRE_NEW

  • PROPAGATION.NESTED

1、准备例子

就是两个常规的Service,我们用A 去调用 B, A 方法固定采用REQUIRED ,B方法分别采用REQUIRED/REQUIRED_NEW/NESTED中的一种,然后在两个方法后分别加上异常看看回滚情况

  // A Service
@Service
public class TestAImpl implements TestAService {
@Resource
private TestBService testBService;
@Resource
private TestMapper testMapper; @Override
@Transactional(rollbackFor = Exception.class , propagation = Propagation.REQUIRED)
public void testA() {
testMapper.insertData(null,"testA");
testBService.testB();
}
} // B Service
@Service
public class TestBImpl implements TestBService {
@Resource
private TestAService testAService; @Resource
private TestMapper testMapper; @Override
@Transactional(rollbackFor = Exception.class , propagation = Propagation.REQUIRED/REQUIRED_NEW/NESTED)
public void testB() {
testMapper.insertData(null,"testB");
}
}

首先我们要知道A调用B,如果B抛出异常在A中不捕获的话,那A是会正常回滚的,所以在测试REQUIRED_NEW/NESTED的时候记得在A中捕获B的异常

结果:

  • REQUIRED: 无论A异常还是B异常,双方都会回滚(注意不要捕获异常)

  • REQUIRED_NEW:因为B是独立的事务,所以A异常:A回滚,B不会回滚;B异常:B回滚,A不会回滚(前提是A要捕获B的异常,否则异常就会自己向上抛,也就影响了A)

  • NESTED:因为B是嵌套的事务,所以A异常,A和B都会回滚;B异常,B回滚,A不会回滚(前提是A要捕获B的异常,否则异常就会自己向上抛,也就影响了A)

2、总结

所以综合来看,最容易产生歧义的就是REQUIRED_NEW和NESTED,用这两者的时候记得要捕获B的异常,否则异常向上抛就没意义了,而这两个最大的区别就是一个是独立,一个是嵌套,独立则是父方法和子方法相互不影响,嵌套则是父方法影响子方法,而子方法不会影响父方法

三、原理

该注解的原理就是AOP,既然是AOP那就是动态代理,与AOP里面其他通知处理方法一样,该注解一样有一个拦截器处理方法,那就是TransactionInterceptor

源代码如下:

所以最终执行的的处理方法就是这个this.invokeWithinTransaction,该方法就是父类的方法,感兴趣的可以自己去看一下:

TransactionAspectSupport.invokeWithinTransaction

AOP最后执行的就是一个拦截器链条嘛。这个事务拦截器也会被放到链条里面去执行,有没有想过AOP里面的方法异常了,事务会回滚吗 ?

AOP通知方法异常会回滚吗 ?

正常情况下会回滚,拦截器链执行顺序与优先级有关,所以正常情况下这个事务会涵盖所有,但是你要是搞AOP的时候设置的优先级高过了事务的优先级,那事务就寄了,同理,你要是在AOP里面把异常给捕获处理了,那最外层感知不到事务自然也寄了

默认的排序如下:

三、失效场景

在Spring中,@Transactional 注解失效的场景通常与代理机制、事务传播行为、异常处理和配置问题有关。以下是常见的失效场景及详细解释:

1、方法内部调用(自调用问题)

场景,在同一个类中,非事务方法调用事务方法,导致事务不生效:

原因

  • Spring事务基于AOP代理实现,只有通过代理对象调用的方法才会被拦截

  • 内部调用(this.updateProfile())绕过了代理对象,直接调用原始方法,事务切面未被触发

  • 代理对象是通过外部调用来拦截的,而内部调用绕过了代理

解决方案

  • 新建一个Service,将方法迁移过去,有点麻瓜
  • 在当前类注入自己,调用updateProfile时通过注入的userService调用

2、异常未正确抛出或被捕获

场景1:未抛出异常

场景2:抛出检查型异常(非RuntimeException)

原因

  • 默认情况下,Spring事务仅在抛出RuntimeException或Error时回滚。

  • 检查型异常(如IOException)需显式配置rollbackFor。

解决方案

  • 显式指定回滚异常:

3、数据库引擎不支持事务

场景:使用不支持事务的存储引擎(如MySQL的MyISAM),即使配置了@Transactional,事务也不会生效

解决方案:改用支持事务的引擎(如MySQL的InnoDB)

4、方法访问权限限制

场景:事务方法被定义为private、final或static

原因:Spring事务基于动态代理(JDK或CGLIB),无法代理私有 或 final方法

解决方案:确保事务方法是public且非final

5、事务传播行为配置不当

场景:嵌套事务中传播行为配置错误

若methodA和methodB在同一个类中,methodB的事务可能不会生效(自调用问题)

解决方案:将methodB移到另一个Bean中,确保通过代理调用

6、多数据源未明确指定事务管理器

场景:项目中使用多个数据源,但未指定事务管理器

解决方案

  • 显式指定事务管理器:

7、多数据源未明确指定事务管理器

场景:未在配置类中启用事务管理

解决方案:添加@EnableTransactionManagement注解

8、异步方法中事务不传播

场景:在异步方法中使用事务

原因:异步方法在新线程中执行,默认事务上下文不会跨线程传播

这个场景我们要尤其注意!

给大家举个例子

主线程A调用线程B保存Id为1的数据,然后主线程A等待线程B执行完成再通过线程A查询id为1的数据。

这时你会发现在主线程A中无法查询到id为1的数据。因为这两个线程在不同的Spring事务中,本质上会导致它们在Mysql中存在不同的事务中。

Mysql中通过MVCC保证了线程在快照读时只读取小于当前事务号的数据,在线程B显然事务号是大于线程A的,因此查询不到数据。

解决方案:手动传递事务上下文(需配合事务管理器配置)

总结

情况如下:内部方法调用、异常类型不匹配、数据库引擎不支持、方法访问权限问题、事务未启用、多线程问题、异常被捕获、数据源配置错误、嵌套事务配置错误以及配置问题等。需要逐一检查这些方面来确定具体原因

事务注解@Transactional的更多相关文章

  1. SpringBoot事务注解@Transactional

    SpringBoot提供了非常方便的事务操作,通过注解就可以实现事务的回滚,非常方便快捷,下面我们就说一下如何进行事务操作. 1. 事务说明 在Spring中,事务有两种实现方式,分别是编程式事务管理 ...

  2. Spring学习之事务注解@Transactional

    今天学习spring中的事务注解,在学习Spring注解事务之前需要明白一些事务的基本概念: 事务:并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通 ...

  3. Springboot 事务注解--- @Transactional

    spring boot @Transactional事物处理    spring boot 添加事物使用 @Transactional注解 简单使用 在启动类上方添加 @EnableTransacti ...

  4. 《四 spring源码》spring的事务注解@Transactional 原理分析

    先了解什么是注解 注解 Jdk1.5新增新技术,注解.很多框架为了简化代码,都会提供有些注解.可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件. 注解不会也不能影 ...

  5. JPA的事务注解@Transactional使用总结

    在项目开发过程中,如果您的项目中使用了Spring的@Transactional注解,有时候会出现一些奇怪的问题,例如: 明明抛了异常却不回滚? 嵌套事务执行报错? ...等等 很多的问题都是没有全面 ...

  6. Spring事务注解@Transactional回滚问题

    Spring配置文件,声明事务时,如果rollback-for属性没有指定异常或者默认不写:经测试事务只回滚运行时异常(RuntimeException)和错误(Error). <!-- 配置事 ...

  7. Spring 事务注解@Transactional

    事务管理一般有编程式和声明式两种,编程式是直接在代码中进行编写事物处理过程,而声名式则是通过注解方式或者是在xml文件中进行配置,相对编程式很方便. 而注解方式通过@Transactional 是常见 ...

  8. Spring事务注解@Transactional失效的问题

    在项目中发现事务失效,使用@Transactional注解标注的Service业务层实现类方法全部不能回滚事务了,最终发现使用因为Spring与shiro进行整合之后导致的问题,将所有的Service ...

  9. 为什么阿里规定需要在事务注解@Transactional中指定rollbackFor?

    作者:Mint6 来源:http://39sd.cn/53D5D Java阿里巴巴规范提示:方法[edit]需要在Transactional注解指定rollbackFor或者在方法中显示的rollba ...

  10. Spring事务管理者与Spring事务注解--声明式事务

    1.在Spring的applicationContext.xml中配置事务管理者 PS:具体的说明请看代码中的注释 Xml代码: <!-- 声明式事务管理的配置 --> <!-- 添 ...

随机推荐

  1. 使用Python的一维卷积

    学习&转载文章:使用Python的一维卷积 背景 在开发机器学习算法时,最重要的事情之一(如果不是最重要的话)是提取最相关的特征,这是在项目的特征工程部分中完成的. 在CNNs中,此过程由网络 ...

  2. rust体验感受,Rust标准库需要还需加强

    了解到Rust的跨平台编译和安全性,尝试用rust写一个http调用的程序,换了几个http client库都失败了,感觉rust语言还有较大的进步空间. 环境 OS: windows 11 rust ...

  3. 深入探讨数据库索引类型:B-tree、Hash、GIN与GiST的对比与应用

    title: 深入探讨数据库索引类型:B-tree.Hash.GIN与GiST的对比与应用 date: 2025/1/26 updated: 2025/1/26 author: cmdragon ex ...

  4. 目前get到最好用的内网穿透软件

    官网:https://www.natfrp.com/ 软件名称:SakuraLauncher 不花钱可以获取到两个隧道,如果不想花钱的话,每天签到领流量即可 之前用过cpolar,飞鸽,ngrok,但 ...

  5. 解决使用yarn安装依赖出现“The engine "node" is incompatible with this module. Expected version "^14.18.0 || ^16.14.0 || >=18.0.0". Got "17.9.0"”的问题

    1.问题描述 某天在使用yarn安装依赖的时候,突然出现如下错误导致安装依赖终止: The engine "node" is incompatible with this modu ...

  6. AllPairs工具助力正交表测试用例设计

    AllPairs工具助力正交表测试用例设计 正交表法是一种高效的测试方法,特别适用于软件测试中需要处理多个控件及其多种取值组合的情况.以下是对正交表法的详细解释: 一.正交表法概述 正交表法是一种利用 ...

  7. Luogu P9055 [集训队互测 2021] 数列重排 题解 [ 紫 ] [ 构造 ] [ 数学 ]

    数列重排:差点就场切的神仙构造,最后一步想假了,导致我模拟赛荣获 25+5+0 的好成绩! 这题部分分很有启发性,跟着一步一步打基本能想到正解的构造,但也有可能想偏部分分的意思,想假策略. 构造 先看 ...

  8. 如何给本地部署的DeepSeek投喂数据,让他更懂你

    写在前面 在上一篇文章中,我们说了怎么在本地部署DeepSeek.对本地部署DeepSeek感兴趣的小伙伴看过来. 本地部署 DeepSeek:小白也能轻松搞定! 话说回来了,为啥要本地部署呢? ① ...

  9. 小米9刷twrp Rec 以及写入Magisk详细教程

    首先手机必须先解锁BL锁才能继续: ---------------------- 小米官方BL解锁教程:点此看教程 ---------------------- 解完锁后开始操作: 工具包:点此下载 ...

  10. Azure Databricks - [02] 常用SQL

    查看当前所在catalog:select current_catalog(); 创建catalog:create catalog if not exists harley_test; 创建表 crea ...