Spring spring

Spring中文网站 > Spring 框架安全 > Spring事务的实现方式有哪些 Spring事务失效解决方案
Spring事务的实现方式有哪些 Spring事务失效解决方案
发布时间:2026/06/30 14:39:49

品牌型号:联想ThinkPad X1

系统:Windows10家庭版

软件版本:Spring 5.3.7

事务是我们在用Spring做项目的时候很容易踩坑的地方之一,总以为加了@Transactional就完事了,结果数据库里一查,数据还是出现异常,事务完全没有生效。这种情况在项目中有很多。想要用好事务,我们要先理清楚Spring事务有哪些实现方式,再理解事务为什么会失效、怎么排查解决。这两个问题想清楚了,事务相关的问题基本就能完全掌握。下面就给大家介绍一下Spring事务的实现方式有哪些,Spring事务失效解决方案的相关内容。

一、Spring事务的实现方式有哪些

事务的实现方式中常用的是声明式事务,也就是@Transactional注解,只需要加在方法上或者类上,Spring就会自动在方法执行前开启事务,正常结束提交,抛出异常回滚,整个过程不需要我们去手动干预,而且业务逻辑和事务控制分开,现在企业项目里用得多。

声明式事务
图1:声明式事务

还有编程式事务,通过TransactionTemplate手动控制事务的开启、提交和回滚。写法大概是这样,我们把业务逻辑包在transactionTemplate.execute()里,需要回滚的时候调用status.setRollbackOnly(),这种方式比注解繁琐,但控制粒度更细,更适合事务范围需要动态决定,或者只想对某几行代码加事务而不是整个方法的场景。

编程式事务
图2:编程式事务

实现事务也有更底层的方式,直接用PlatformTransactionManager手动管理事务,调getTransaction开启,调commit提交,调rollback回滚,完全手动控制,灵活度很高,但代码量也大,实际业务开发基本不会这么用。

手动管理事务
图3:手动管理事务

这三种方式中声明式事务覆盖了绝大多数场景,平时我们开发的时候直接用@Transactional就够了,在处理一些注解方式搞不定的细粒度控制需求时,可以用编程式事务作为补充,至于偏底层的PlatformTransactionManager,大家了解一下原理就行。

二、Spring事务失效解决方案

如果遇到事务失效的情况,大概率是因为同类内部方法调用,例如方法A调用同一个类里的方法B,B上加了@Transactional,事务无法生效,因为内部调用走的是原始对象,绕过了代理,事务逻辑根本没机会触发。只需要把B抽到另一个Bean里,通过注入的方式调用就可以了。或者通过AopContext.currentProxy()拿到当前代理对象再调用,但这种写法侵入性强,不太推荐,能拆就拆。

this调用,绕过AOP代理
图4:this调用,绕过AOP代理

也可能是因为异常类型不对,@Transactional默认只在抛出RuntimeException和Error的时候回滚,checked异常不会触发回滚。业务里如果抛的是Exception或者自定义的checked异常,事务该提交还是提交,数据不会回滚。

解决方法很简单,注解上加rollbackFor = Exception.class,明确指定遇到所有异常都回滚,这个习惯值得我们养成,可以在写@Transactional的时候顺手加上。

编译器受检Exceptions不回滚
图5:编译器受检Exceptions不回滚

还有一种情况是异常被吞掉了,方法里用了try-catch把异常捕获了但没有重新抛出,Spring感知不到有异常发生,事务正常提交,排查这类问题要看代码里有没有把异常静默处理掉。如果异常需要捕获做一些处理,记得在catch里把异常重新抛出,或者手动调TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()标记回滚。这几种情况加起来,覆盖了项目里大部分事务失效的场景。

吞异常导致事务失效
图6:吞异常导致事务失效

以上就是Spring事务的实现方式有哪些,Spring事务失效解决方案的全部内容了。Spring事务用起来不复杂,@Transactional加上去基本能应付大多数场景,编程式事务作为补充处理特殊情况就够了。如果遇到事务失效,这种情况才是真正需要上心的地方,内部调用绕过代理、异常类型不对、方法是私有的、异常被吞,把这几种情况记清楚,遇到事务不生效的问题,顺着这几个方向排查,基本能很快定位到原因。

180 1563 6924