如果使用了@Async异步方法上面添加了@Transactional,那这个事务是不会生效的
场景复现:
@Transactional 基于MethodInterceptor实现的,所以在方法执行完毕之后才会提交事务
上面代码前面操作位正常保存或者更新操作,代码最后调用了一个异步方法,这个异步方法为了避免主从延迟,直接查询了主库刚才保存的信息,但是有时候能查询到,有时候查询不到数据,
简单分析后,异步线程开始查询的时候,有几率主线程的事务还未提交完成,当前数据库的隔离级别为可重复读,异步线程有很大概率还是读取不到数据的,
解决办法:
应对这个问题第一种方法
可以将异步方法改为异步延迟队列,等待几秒之后可以直接查询从库,这时候按道理会查询到数据的,
第二种方法
捕获异步方法里面的异常,如果发现抛出的异常是记录不存在,可以进行重试,
但是这种方法都不确保也不稳妥,方法1可能延迟时间控制不好,方法2可能重复执行多次
在AbstractPlatformTransactionManager中可以找到在事务的生命周期中提供了很多的扩展接口,我们可以在扩展接口上做处理
可以根据自己需要实现TransactionSynchronization的方法,其中afterCommit方法表示事务提交成功之后调用的方法,这个时候事务已经持久化,我们可以在这个里面直接调用异步方法
修改后的方法如下:
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {@Overridepublic void afterCommit() {async();}});