大家肯定对@Transactional这个注解很熟悉,也对事务有着详细的了解,也知道多个数据库操作需要通过事务来保证一致性和原子性。但是很少会关注事务是否生效、有没有出错。这类问题也比较难在测试阶段发现,当出现线上问题的时候不可避免的会产生大量脏数据。所以这次我分享的内容就是帮助大家理清楚使用@Transactional的思路,避免使用不当产生bug。
事务为什么不生效
很多同学以为只要加了这个注解就不需要管它了,其实不尽然。可以看看下述例子:
1 |
|
- 只有定义在public方法上的 @Transactional 才能生效
1 | public int createUserWrong2(String name) { |
- 必须通过代理过的类从外部调用目标方法才能生效
1 |
|
- 只有异常传播出了标记了 @Transactional 注解的方法,事务才能回滚
1 | /** |
- 默认出现 RuntimeException(非受检异常)或 Error 的时候,Spring 才会回滚事务(可以指定回滚异常)
事务传播
有现在这个场景,注册主会员和注册子用户,要求注册子用户失败不影响主会员的注册,下述伪代码,可以猜一下结果
1 |
|
上述代码异常跑出了@Transactional 注解标记的 createUserWrong 方法,Spring 会回滚事务
修改之后如下:
1 |
|
虽然捕获了异常,但是因为没有开启新事务,而当前事务因为异常已经被标记为rollback了,所以最终还是会回滚。
看到这里就清楚了,只能让处理子用户的逻辑运行在单独的事务中,这就用到了SPRING的事务传播机制
1 |
|
希望这次分享能帮助大家正确处理业务代码中的事务。
实际使用踩的坑
多数据源中不能使用事务
事务和分布式锁使用的坑
现象:业务中加了分布式锁,也做了幂等处理如果业务ID存在相同的数据则直接返回。但还是会生成2条一样的数据。
1 |
|
1 |
|
结论:当使用分布式锁和事务时,因为切面处理是用的先进后出的栈,又因为事务处理的优先级是默认最低的,所以如果没有知道分布式锁的优先级就会导致锁先于事务释放,导致可能出现事务的隔离性被破坏,产生脏数据。
原文链接: https://alexhuihui.github.io/article/20240118.html
版权声明: 转载请注明出处.