解决方案: 配置rollbackFor eg. 配置@Transactional(rollbackFor = Exception.class)
2.选用了错误的事务传播机制 例如 @Transactional(propagation = Propagation.NOT_SUPPORTED)
有事务挂起 ,无事务就以非事务的方式执行。
3.业务自身捕捉到异常[try catch finally] 而不是通过抛出异常交给类处理
因为spring事务只有捕捉到了业务抛出去的异常,才能进行后续的处理,如果业务自己捕获了异常,则事务无法感知。
解决方案:将异常原样抛出 尽量不要在业务方法中使用try...catch来捕获你的异常,防止影响了事务。
4.跨了线程的事务
原因:如果事务方法内,开启了新线程去执行其他事务方法也是不受当前事务方法控制的。因为不同线程拥有的threadlocal 不一样。
所以:当你需要明确开启新线程,请分开处理。
5.@Transactional放在非public方法上。
原因:AbstractFallbackTransactionAttributeSource类调用computeTransactionAttribute()时,过滤了非public方法上事务配置信息(相当于没有配置无事务运行机制)。
什么是传播事务:事务是数据库的一种特性,而Spring只是封装这个特性,方便我们使用,最终的执行实际上都是在数据库中完成,但是对于数据库来说,事务是单一的,没有那么多业务场景,但是对于Spring来说,会面对各种各样的业务需求,所以需要有一套可以从代码层面去控制事务来满足我们的场景需求,所以也就有了传播机制。
事务传播机制是通过@Transactional实现得,使用了ThreadLocal实现得 ,保证事务方法拿到的数据库连接是同一个呢?答案就是使用了ThreadLocal。
我们平时开发不可能所有数据库操作都在一个方法里,之前说过保证事务的很重要的一点是始终用一个连接connection,所以被调用方法里有操作数据库时也需要用这个主方法中创建的connection。
因为不太可能把所有调用方法都加一个connection入参,所以比较优雅的方法是把连接放在ThreadLocal里,其他方法要操作数据库时就从ThreadLocal里get即可。
posted on
浙公网安备 33010602011771号