非public修饰方法会导致事务失效:Spring声明式事务基于AOP动态代理实现,对方法访问权限有严格要求,非public修饰的方法Spring动态代理无法正常拦截,事务注解会被忽略,事务无法生效
事务方法所在类未被Spring容器管理会导致事务失效:Spring 只会对容器内的 Bean 进行扫描、解析注解(包括 @Transactional),并通过动态代理为符合条件的 Bean 生成事务增强的代理对象,若类未被 Spring 容器管理(即不是 Spring Bean),Spring 无法感知该类的存在,更无法对其方法进行事务代理增强,@Transactional 注解会被完全忽略,事务自然无法生效
方法被final修饰会导致事务失效:final 修饰符的特性是:被 final 修饰的方法无法被重写,被 final 修饰的类无法被继承。对应到 Spring 事务:
- 若事务方法被 final 修饰,即使使用 CGLIB 动态代理,也无法在子类中重写该方法来添加事务增强逻辑
- JDK 动态代理更无法处理 final 方法,最终 Spring 无法为该方法生成带事务增强的代理,@Transactional 注解失效
同类内部方法调用(非代理对象调用)会导致事务失效:Spring事务实现依赖代理对象而非原始对象,只有通过代理对象调用事务方法才能触发事务的增强逻辑。在同一个类中,一个非事务方法直接调用同类中的事务方法时,本质是原始对象内部调用没有经过代理对象,Spring无法拦截到事务方法的调用,导致事务注解失效
异常被捕获未抛出导致事务无法回滚:Spring 事务的回滚机制依赖未被捕获的异常,只有当事务方法抛出(符合回滚条件)的异常,且该异常未被方法内部捕获消化,Spring 才能感知到异常并触发事务回滚。若在事务方法内部使用 try-catch 捕获了异常,且未在 catch 块中重新抛出异常(或手动触发回滚),Spring 无法感知异常发生,会认为事务执行成功,最终提交事务,导致数据不一致
抛出非检查异常(默认不支持)导致事务不回滚:Spring 声明式事务默认只支持回滚(运行时异常)(RuntimeException 及其子类)和(错误)(Error),对于(受检异常)(Checked Exception,即编译时必须捕获的异常,如 IOException、SQLException),默认不会触发事务回滚。若事务方法抛出了受检异常,且未配置 @Transactional 的 rollbackFor 属性,事务会正常提交,导致失效
事务传播属性配置不当导致失效:Spring 事务提供了多种传播属性(通过 @Transactional(propagation = ...) 配置),用于定义事务方法被调用时的事务行为。其中部分传播属性会导致事务失效,最典型的是:
- Propagation.NOT_SUPPORTED:以非事务方式运行,若当前存在事务,则挂起当前事务,事务失效
- Propagation.NEVER:以非事务方式运行,若当前存在事务,则抛出异常,事务失效
- Propagation.SUPPORTS:仅当当前存在事务时才加入事务,否则以非事务方式运行(无事务环境下失效)
数据库存储引擎不支持事务导致失效:Java 事务的最终落地依赖数据库的事务支持,若使用的数据库存储引擎不支持事务,即使 Spring 配置正确,事务也无法生效。最典型的例子:MySQL 的 MyISAM 存储引擎不支持事务(无回滚、提交机制),而 InnoDB 存储引擎支持完整的 ACID 事务特性
多线程使用不当会导致事务失效:Spring 声明式事务的核心是事务与当前线程绑定,简单来说:一个事务无法跨多个独立线程,不同线程的事务相互隔离,父线程事务无法管控子线程的数据库操作