拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot事务失效的6个坑,你踩过几个

SpringBoot事务失效的6个坑,你踩过几个

在Spring Boot开发中,@Transactional注解看似简单,却暗藏玄机。很多开发者以为加上注解就万事大吉,结果生产环境出现数据不一致时才发现事务早已失效。事务失效也是面试中高频的追问点,能准确说出几种失效场景,往往能体现你对Spring AOP和事务机制的真正理解。下面这6个坑,看看你踩过几个。

坑1:方法不是public

Spring事务基于AOP代理实现,而代理只能拦截public方法。如果你把@Transactional标在protected、private或包级方法上,事务不会生效,而且Spring通常不会报错,只是静默忽略。

示例:

java
复制
下载
@Transactional protected void updateStock() { ... } // 事务失效

解决:将方法改为public。如果确实需要非public,可以考虑使用AspectJ静态织入,但成本较高。

坑2:自调用导致代理失效

同一个类中,一个非事务方法直接调用另一个带@Transactional的方法,属于this调用,不经过代理对象,事务自然不生效。

示例:

java
复制
下载
public void createOrder() { this.updateInventory(); // 自调用,事务失效 } @Transactional public void updateInventory() { ... }

解决:注入自身代理、使用AopContext.currentProxy(),或者将事务方法拆分到另一个Bean中。最推荐拆分,职责清晰且无代理陷阱。

坑3:异常类型不匹配

Spring默认只对RuntimeException和Error回滚。如果你抛出的是检查型异常(如IOException、SQLException),事务默认不回滚,数据可能部分提交。

示例:

java
复制
下载
@Transactional public void save() throws IOException { // 抛出IOException,事务不回滚 }

解决:明确指定@Transactional(rollbackFor = Exception.class),覆盖所有异常。这是最稳妥的做法。

坑4:异常被捕获吞掉

方法内部用try-catch捕获了异常,却没有重新抛出,Spring认为方法正常执行完毕,于是提交事务。

示例:

java
复制
下载
@Transactional public void transfer() { try { // 业务操作 } catch (Exception e) { log.error("失败", e); // 异常被吞,事务提交 } }

解决:catch后重新抛出RuntimeException,或者手动调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()标记回滚。

坑5:多数据源未指定事务管理器

当项目配置了多个数据源和多个PlatformTransactionManager时,@Transactional默认使用primary事务管理器。如果你操作的是另一个数据源,事务不会生效。

示例:

java
复制
下载
@Transactional // 默认用primary,但操作的是second数据源 public void updateSecondDB() { ... }

解决:显式指定@Transactional(transactionManager = "secondTransactionManager"),确保与数据源匹配。

坑6:传播行为配置错误

传播行为决定了事务如何嵌套。常见错误是在事务方法中调用标记为NOT_SUPPORTED的方法,导致当前事务被挂起,部分操作脱离事务;或者误用REQUIRES_NEW,使内外事务相互独立,外层回滚不影响内层。

示例:

java
复制
下载
@Transactional public void outer() { innerService.doWithNotSupported(); // 当前事务挂起,操作无事务 }

解决:理解各传播行为语义,按业务需求选择。默认REQUIRED适合大多数场景;需要独立提交时用REQUIRES_NEW,但要清楚其代价。

总结

事务失效的本质离不开三点:代理机制、异常处理、配置错误。日常开发中,建议养成以下习惯:事务方法一律public;避免自调用;统一使用rollbackFor = Exception.class;不要吞异常;多数据源显式指定事务管理器;搞不清传播行为时保持默认。此外,确保数据库表引擎为InnoDB,否则再正确的注解也无济于事。面试中如果能结合AOP代理原理讲清这些坑,你离offer就更近了一步。

返回列表