@Transactional注解事务失效的几种原因

news/2024/2/28 10:09:20

@Transactional注解事务失效的几种原因

  • 一、异常被捕获后没有抛出
  • 二、抛出非运行时异常
  • 三、同一个类中方法内部直接调用
    • 3.1 失效原因
    • 3.2 解决办法
      • 3.2.1 新加一个service方法
      • 3.2.2 在该 Service 类中注入自己
      • 3.2.3 通过 AopContent 类
  • 四、未被Spring管理
  • 五、新开启一个线程
  • 六、访问权限问题
  • 七、方法用final修饰
  • 八、数据库本身不支持
  • 九、事务传播属性设置错误
  • 其他
    • 1、大事务问题
    • 2、编程式事务

一、异常被捕获后没有抛出

如果想要 spring 事务能够正常回滚,必须抛出它能够处理的异常。如果没有抛异常,或者自己吞掉了异常没有抛出,则 spring 认为程序是正常的。因此也不会回滚。

二、抛出非运行时异常

spring 事务,默认情况下只会回滚RuntimeException(运行时异常)和Error(错误),对于普通的 Exception(非运行时异常),它不会回滚。

如果事务注解使用的是@Transactional(),即使异常抛出了,但是抛出的是非RuntimeException类型异常,同样也不会回滚。
如果事务注解使用的是@Transactional(rollbackFor = Exception.class),那么抛出的是非RuntimeException类型异常是可以回滚的。

注: 也就是说,如果抛的异常不正确,spring 事务也不会回滚。

比如,方法上的事务是:@Transactional(rollbackFor = BusinessException.class),而实际执行业务逻辑时,程序报错,抛了 SqlException、DuplicateKeyException 等异常。而 BusinessException 是我们自定义的异常,报错的异常不属于 BusinessException,所以事务也不会回滚。

所以,建议一般情况下,将该参数设置成:Exception 或 Throwable。

三、同一个类中方法内部直接调用

3.1 失效原因

这种场景很常见,方法A调用方法B,其中方法A未使用事务,而方法B使用了事务,此时方法B的事务是不生效的,例子如下,因为updateStatus 方法拥有事务的能力是因为 spring aop 生成代理了对象,但是这种方法直接调用了 this 对象的方法,所以 updateStatus 方法不会生成事务。
例子:

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public void add(UserModel userModel) {userMapper.insertUser(userModel);updateStatus(userModel);}@Transactionalpublic void updateStatus(UserModel userModel) {doSameThing();}
}

3.2 解决办法

3.2.1 新加一个service方法

这个方法非常简单,只需要新加一个 Service 方法,把 @Transactional 注解加到新 Service 方法上,把需要事务执行的代码移到新方法中。具体代码如下:

@Servcie
public class ServiceA {@Autowiredprvate ServiceB serviceB;public void save(User user) {queryData1();queryData2();serviceB.doSave(user);}}@Servciepublic class ServiceB {@Transactional(rollbackFor=Exception.class)public void doSave(User user) {addData1();updateData2();}}

3.2.2 在该 Service 类中注入自己

如果不想再新加一个 Service 类,在该 Service 类中注入自己也是一种选择。具体代码如下:

@Servcie
public class ServiceA {@Autowiredprvate ServiceA serviceA;public void save(User user) {queryData1();queryData2();serviceA.doSave(user);}@Transactional(rollbackFor=Exception.class)public void doSave(User user) {addData1();updateData2();}}

3.2.3 通过 AopContent 类

在该 Service 类中使用 AopContext.currentProxy() 获取代理对象。

上面的方法 2 确实可以解决问题,但是代码看起来并不直观,还可以通过在该 Service 类中使用 AOPProxy 获取代理对象,实现相同的功能。具体代码如下:

@Servcie
public class ServiceA {public void save(User user) {queryData1();queryData2();((ServiceA)AopContext.currentProxy()).doSave(user);}@Transactional(rollbackFor=Exception.class)public void doSave(User user) {addData1();updateData2();}}

四、未被Spring管理

在我们平时开发过程中,有个细节很容易被忽略,即使用 spring 事务的前提是:对象要被 spring 管理,需要创建 bean 实例。
通常情况下,我们通过 @Controller、@Service、@Component、@Repository 等注解,可以自动实现 bean 实例化和依赖注入的功能。
如果有一天,你匆匆忙忙地开发了一个 Service 类,但忘了加 @Service 注解,那么该类不会交给 spring 管理,所以它的 add 方法也不会生成事务。

五、新开启一个线程

在实际项目开发中,多线程的使用场景还是挺多的。如果 spring 事务用在多线程场景中,会有问题吗?
如果两个方法不在同一个线程中,那么获取到的数据库连接不一样,从而是两个不同的事务。
spring 的事务是通过数据库连接来实现的。当前线程中保存了一个 map,key 是数据源,value 是数据库连接。
我们说的同一个事务,其实是指同一个数据库连接,只有拥有同一个数据库连接才能同时提交和回滚。如果在不同的线程,拿到的数据库连接肯定是不一样的,所以是不同的事务。

六、访问权限问题

众所周知,java 的访问权限主要有四种:private、default、protected、public,它们的权限从左到右,依次变大。
如果方法的访问权限被定义成了private,这样会导致事务失效,spring 要求被代理方法必须是public的。

七、方法用final修饰

spring 事务底层使用了 aop,也就是通过 jdk 动态代理或者 cglib,帮我们生成了代理类,在代理类中实现的事务功能。
但如果某个方法用 final 修饰了,那么在它的代理类中,就无法重写该方法,而添加事务功能。

注意:如果某个方法是 static 的,同样无法通过动态代理,变成事务方法。

八、数据库本身不支持

众所周知,在 mysql5 之前,默认的数据库引擎是myisam。

它的缺点就是不支持事务,因此在mysql5之后,myisam逐渐退出了历史的舞台,取而代之的是Innodb。

九、事务传播属性设置错误

我们在使用@Transactional注解时,是可以指定propagation参数的。
该参数的作用是指定事务的传播特性,spring 目前支持 7 种传播特性:

  • REQUIRED 如果当前上下文中存在事务,则加入该事务,如果不存在事务,则创建一个事务,这是默认的传播属性值。
  • SUPPORTS 如果当前上下文中存在事务,则支持事务加入事务,如果不存在事务,则使用非事务的方式执行。
  • MANDATORY 当前上下文中必须存在事务,否则抛出异常。
  • REQUIRES_NEW 每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
  • NOT_SUPPORTED 如果当前上下文中存在事务,则挂起当前事务,然后新的方法在没有事务的环境中执行。
  • NEVER 如果当前上下文中存在事务,则抛出异常,否则在无事务环境上执行代码。
  • NESTED 如果当前上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。

目前只有这三种传播特性才会创建新事务:REQUIRED,REQUIRES_NEW,NESTED。设置其他传播特性都不会创建事务。

其他

1、大事务问题

例:

@Service
public class UserService {@Autowired private RoleService roleService;@Transactionalpublic void add(UserModel userModel) throws Exception {query1();query2();query3();roleService.save(userModel);update(userModel);}
}@Service
public class RoleService {@Autowired private RoleService roleService;@Transactionalpublic void save(UserModel userModel) throws Exception {query4();query5();query6();saveData(userModel);}
}

但@Transactional注解,如果被加到方法上,有个缺点就是整个方法都包含在事务当中了。

上面的这个例子中,在 UserService 类中,其实只有这两行才需要事务:

roleService.save(userModel);
update(userModel);

在 RoleService 类中,只有这一行需要事务:

saveData(userModel);

现在的这种写法,会导致所有的 query 方法也被包含在同一个事务当中。

如果 query 方法非常多,调用层级很深,而且有部分查询方法比较耗时的话,会造成整个事务非常耗时,而从造成大事务问题。

2、编程式事务

上面聊的这些内容都是基于@Transactional注解的,主要说的是它的事务问题,我们把这种事务叫做:声明式事务。

其实,spring 还提供了另外一种创建事务的方式,即通过手动编写代码实现的事务,我们把这种事务叫做:编程式事务。例如:

 @Autowiredprivate TransactionTemplate transactionTemplate;...public void save(final User user) {queryData1();queryData2();transactionTemplate.execute((status) => {addData1();updateData2();return Boolean.TRUE;})}

在 spring 中为了支持编程式事务,专门提供了一个类:TransactionTemplate,在它的 execute 方法中,就实现了事务的功能。

相较于@Transactional注解声明式事务,我更建议大家使用基于TransactionTemplate的编程式事务。主要原因如下:

  1. 避免由于 spring aop 问题导致事务失效的问题。
  2. 能够更小粒度地控制事务的范围,更直观。

建议在项目中少使用 @Transactional 注解开启事务。但并不是说一定不能用它,如果项目中有些业务逻辑比较简单,而且不经常变动,使用 @Transactional 注解开启事务也无妨,因为它更简单,开发效率更高,但是千万要小心事务失效的问题。


http://www.ppmy.cn/news/121531.html

相关文章

DC1通关

环境自己百度装好。 我的一台kali,一台DC都是52网段 1.nmap 扫一扫52网段 确定是143,然后针对143进行扫描 80开放,进去。 老熟人了 Drupal,直接msf开打 试了几个,use2直接getshell了 看看权限 尝试SUID提权 进入sh…

轻松白嫖GPT-4,已经标星38K,不再害怕高昂的AI模型费用!

文章目录 白嫖GPT-4当前可白嫖站点 白嫖GPT-4 计算机专业学生xtekky在GitHub上发布了一个名为gpt4free的开源项目,该项目允许您免费使用GPT4和GPT3.5模型。这个项目目前已经获得了380000颗星。 开源地址:https://github.com/xtekky/gpt4free 简而言之&a…

通达信凹口平量柱选股公式,倍量柱之后调整再上升

凹口平量柱是一组量柱形态,表现为量柱两边高、中间扁平或圆底的形态。如下图所示,左右各有一根高度持平的高量柱,中间夹杂着三五根甚至更多根低量柱。 凹口平量柱选股公式需要结合量柱以及K线,主要考虑以下三点: 1、倍…

深度学习 - 52.推荐场景的多样性与 MMR [Maximal Marginal Relevance] 简介与 Python 实现

目录 一.引言 二.多样性 三.MMR 流程 1.标准 MMR 2.窗口 MMR 四.基于向量内积相似度的 MMR Python 实现 1.模拟用户 rank 结果 2.向量内积计算 MRi 2.1 获取向量计算 max sim 2.2 argmax 获取最优 MRi item 3.MMR 测试 4.MMR 完整代码 五.总结 一.引言 MMR - Ma…

IOS发布:App Store Connect Operation Error。SDK Version Issue.

错误描述: App Store Connect Operation Error SDK Version Issue. This app was built with the iOS 15.0 SDK. all iOS apps submitted to the App Store must be built with the iOS 16.1 SDK or later, included in Xcode 14.1 or later. 问题原因&#xf…

第十五章行为性模式—命令模式

文章目录 命令模式解决的问题结构实例存在的问题适用场景 JDK 源码 - Runnable 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类…

苹果13用哪款耳机的音质好一点?音质好的蓝牙耳机推荐

苹果13用哪款耳机的音质好一点?音质好的蓝牙耳机推荐 近几年,真无线耳机成为了许多消费者的新宠,即连即用,完全没有线缆的束缚,放到收纳盒中不仅携带非常方便,还能快速的进行充电,满足较长时间…

商务耳机有什么推荐?主动降噪耳机盘点

伴随着技术的不断发展和人们对于生活品质要求的不断提高,越来越多的朋友开始升级自己的蓝牙耳机,很多人也因为工作生活的需要,完成了一次“漫长而纠结”的蓝牙耳机选购历程。降噪也成了人们选择耳机的重要条件,接下来就给大家推荐…

springcloudAlibaba整合knife4j整合swagger整合gateway,并且同步到Yapi上

springcloudAlibaba整合knife4j整合swagger整合gateway&#xff0c;并且同步到Yapi上 1.gateway模块 1.pom引入 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version&g…

蓝牙耳机现在品牌这么多究竟该怎么选

自从2017年以来&#xff0c;真无线蓝牙耳机越来越呈现爆发式增长&#xff0c;而Apple AirPods Pro 3代苹果蓝牙耳机的问世&#xff0c;再次让真无线耳机市场的热度达到新的小高峰。真无线耳机各家都有各家的好&#xff0c;造型上大小不一&#xff0c;设计上各有千秋&#xff0c…

android安卓源码海量项目合集打包-1

下载地址 最后更新共计113个分类5177套源码29.2 GB。 卷 新加卷 的文件夹 PATH 列表 卷序列号为 00000200 5E7A:7F30 F:. ├─前台界面 │ ├─3D标签云卡片热门 │ │ Android TagCloudView云标签的灵活运用.rar │ │ Android 实现 标签 拖动 改变位置.rar │ │ android 流…

公众号800篇文章分类和索引

杂货铺的文章&#xff0c;已经积累到800篇了&#xff0c;首先还得谢谢各位读者朋友们&#xff0c;每个在看&#xff0c;每个转发&#xff0c;每个评论&#xff0c;每个点赞&#xff0c;你们的支持&#xff0c;是我坚持的动力&#xff0c;每篇文章的背后&#xff0c;都有自己的成…

公众号900篇文章分类和索引

杂货铺的文章&#xff0c;已经积累到900篇了&#xff0c;写第一篇文章时&#xff0c;没想太多&#xff0c;就是纯粹的兴趣&#xff0c;无论是技术&#xff0c;还是生活&#xff0c;都会有些值得用文字记录的&#xff0c;在让自己温故知新的同时&#xff0c;如果能够帮助一些朋友…

面试 Notes|2021 年秋季 Android 弱鸡艰难求职记。。。

扯犊子之前&#xff0c;先放一张面试图吧&#xff1a; 求职&#xff1f;求生&#xff1f;Start… 说来也怪&#xff0c;从入职的第一天就觉得很不舒服&#xff0c;然后慢慢产生离开的念头&#xff0c;随后转变思想&#xff0c;回去打算按照步骤继续学习&#xff0c;避免下次求…

2020爱分析·智能通讯云厂商全景报告

报告摘要 企业面临业务增长的压力&#xff0c;通讯能力建设成为对内提升运营效率&#xff0c;对外提升产品竞争力和客户体验的重要手段&#xff0c;通讯云的场景应用正在加速渗透。 基于对国内各行业甲方企业的调研&#xff0c;爱分析认为智能通讯云应用呈现以下趋势&#xff1…

AirPods 使用技巧---十大隐藏功能

AirPods 使用技巧 -- 非常好用的10个隐藏功能 AirPods 1、在iPhone上实时查看AirPods电量 通常我们在使用AirPods时想要查看剩余电量&#xff0c;我注意到身边很多人的操作是&#xff1a;把耳机放回充电盒——靠近iPhone——打开充电盒的盖子&#xff0c;这时在iPhone屏幕上会显…

Python 淘宝商品价格爬取(requests库+正则表达式)

淘宝搜索关键词链接&#xff1a;https://s.taobao.com/search?q关键词 第2页商品链接&#xff1a;https://s.taobao.com/search?q关键词&s44 第3页商品链接&#xff1a;https://s.taobao.com/search?q关键词&s88 ... 第n也页商品链接&#xff1a;https://s.taob…

十元的耳塞到万元耳塞,之间到底有什么区别

第一个音质关键词&#xff0c;解析度 解析度可以理解为器材还原音乐细节信息量的多少&#xff0c;是一个耳机耳塞包括音箱最基本的素质&#xff0c;也直接决定了器材的定位和定价。同一首曲子&#xff0c;不同器材让你听到的细节内容是不同的&#xff0c;如果信息量不够&#x…

常见耳机品牌简介及鉴赏

常见耳机品牌简介欧洲三大品牌AKG&#xff1a;国内称“爱科技”。奥地利著名的耳机话筒制造商&#xff0c;1947年成立于维也纳。AKG的耳机轻巧坚固舒适&#xff0c;声音流畅自然&#xff0c;中频优美迷人&#xff0c;声场开阔。它的经典产品有在专业领域具有极高声望的K141系列…

王者荣耀吃鸡哪款蓝牙耳机好用?手游电竞党最爱五款低延迟蓝牙耳机

当你漫步在城市的钢筋水泥&#xff0c;迎面而来的全都是陌生的面孔和令人烦躁的热浪&#xff0c;你或许只想着用什么样的方式来隐藏自己的惶恐与不安&#xff0c;你渴望另一种声音在耳畔震颤来驱散烦躁&#xff0c;当你戴上耳机&#xff0c;独享音乐的那一刻&#xff0c;才算是…
最新文章