java中Spring事务失效的8个常见案例和解决方案
投稿:yin
Spring事务管理是企业级Java应用的核心功能,如果使用不当将会引发严重的生产问题,比如因事务失效带来的数据不一致问题。事务失效往往不会抛出异常,而是静默发生,等到业务出现问题时才被发现,造成严重的数据不一致。本文将分析8种导致Spring事务失效的使用问题并提供相应的解决方案。
一、事务注解应用在非public方法上
问题现象
开发者在非public方法上添加@Transactional
注解,但事务没有生效。
Spring AOP的代理机制默认只拦截public方法。
这是因为事务通知是基于Spring AOP实现的,而Spring AOP默认只拦截public方法调用。
查看AbstractFallbackTransactionAttributeSource
类的源码可以发现:
// AbstractFallbackTransactionAttributeSource.java protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } // ... }
非public方法上的@Transactional
注解会被直接忽略,返回null,导致事务不生效。
解决方案
确保标注@Transactional
的方法为public:
二、同一个类中方法调用
问题现象
在同一个类中,非事务方法调用事务方法,或者事务方法调用另一个具有不同事务属性的方法,事务会失效。
原理分析
解决方案
有几种方法可以解决:
方法1:使用自我注入
方法2:使用AopContext获取代理对象(需要额外配置)
方法3:将方法拆分到不同的类中
三、异常被吞没
问题现象
开发者在事务方法中捕获了异常但没有重新抛出,导致事务无法回滚。
原理分析
解决方案
有两种解决方法:
方法1:重新抛出异常
方法2:使用TransactionAspectSupport手动回滚
四、异常类型不匹配回滚规则
问题现象
开发者抛出了异常,但事务没有回滚。
这通常是因为抛出的异常类型不满足默认的回滚规则。
原理分析
Spring默认只在遇到未检查异常(RuntimeException及其子类)和Error时才回滚事务。
受检异常(如IOException、SQLException)被认为是业务异常,默认情况下不会触发事务回滚。
这是因为@Transactional
注解的默认配置是:
@Transactional(rollbackFor = RuntimeException.class)
解决方案
有两种解决方法:
方法1:指定回滚的异常类型
方法2:将受检异常转换为非受检异常
五、数据库不支持事务
问题现象
所有事务配置看起来都正确,但事务仍然不生效。
原理分析
解决方案
确保使用支持事务的数据库引擎:
- 1. 对于MySQL,使用InnoDB引擎而不是MyISAM
- 2. 检查表的创建语句,确保引擎类型正确:
-- 检查表引擎 SHOW TABLE STATUS WHERE Name = 'your_table_name'; -- 修改表引擎为InnoDB ALTER TABLE your_table_name ENGINE=InnoDB;
六、错误的传播行为设置
问题现象
在嵌套事务场景中,内部事务的回滚没有按照预期工作。
原理分析
Spring提供了不同的事务传播行为,用于控制事务的边界。
最常用的是:
使用不当的传播行为会导致事务范围不符合预期,特别是在异常处理场景中。
解决方案
根据业务需求选择正确的传播行为:
传播行为选择指南:
七、未被Spring管理的类
问题现象
在类上添加了@Transactional
注解,但事务没有生效。
原理分析
解决方案
确保类被Spring容器管理:
@Service // 正确:添加@Service注解 public class UserService { @Autowired private UserMapper userMapper; @Transactional public void createUser(User user) { userMapper.insert(user); throw new RuntimeException("测试"); // 现在事务会正常回滚 } }
同时,确保组件扫描配置正确:
@Configuration @ComponentScan("com.example.service") // 确保包路径正确 public class AppConfig { // ... }
八、事务管理器配置错误
问题现象
使用了正确的事务注解,但事务不生效或者出现异常。
原理分析
Spring支持多种事务管理器,针对不同的持久化技术:
如果配置了错误的事务管理器,或者在多数据源环境中未指定正确的事务管理器,会导致事务失效。
解决方案
单数据源环境:确保配置正确的事务管理器
多数据源环境:指定使用的事务管理器
@Configuration @EnableTransactionManagement public class MultiDatabaseConfig { @Bean public DataSource primaryDataSource() { // 主数据源配置... return new HikariDataSource(); } @Bean public DataSource secondaryDataSource() { // 次数据源配置... return new HikariDataSource(); } @Bean public PlatformTransactionManager primaryTransactionManager() { return new DataSourceTransactionManager(primaryDataSource()); } @Bean public PlatformTransactionManager secondaryTransactionManager() { return new DataSourceTransactionManager(secondaryDataSource()); } } @Service public class UserService { // 指定使用的事务管理器 @Transactional(transactionManager = "primaryTransactionManager") public void createUser(User user) { // 使用主数据源的操作 } @Transactional(transactionManager = "secondaryTransactionManager") public void createUserLog(UserLog log) { // 使用次数据源的操作 } }
总结
到此这篇关于java中Spring事务失效的8个常见案例和解决方案的文章就介绍到这了,更多相关Spring事务失效的8个常见案例内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!