记一次数据库事务问题的定位与解决

技术背景:SpringBoot用SpringMVC + + +的MyBatis的ActiveMQ

问题描述:在服务层中根据主键对某表中数据记录的部分字段进行更新,更新之后使用ActiveMQ的对刚才更新数据的中另外一个字段进行更新,消息队列的更新是后加的,加上之后导致先前的更新失效;

问题分析:经过日志分析,消息队列触发的更新总是拿到服务层中第一次更新前的数据进行更新,所以会将第一次更新的结果进行覆盖因为该服务层中的方法加了事务且设置回滚异常为exception.class。数据库使用的MySQL的,因此隔离级别是可重复读,默认的事务传播级方式是必需的。也就是说消息队列中查询到的数据是第一次更新后尚未提交的数据。原因是在消息队列中消息发送后,方法返回后事务才会提交。

修改方案:

1)将事务的隔离级别设置为最高的序列化级别,这个级别的事务是写读都不会并行的,在第一次更新没有提交之前消息队列中消费者的更新操作是不能进行的,只有等待,也就能解决上述问题;

2)将消息队列中消费者对数据的更新操作使用aop在atfterReturn之后进行;

3)对于消息队列中消费者对数据的更新只更新本更新要更新的字段,避免覆盖前者的更新结果;

方案对比:

方案1代码修改量少,但是序列化级别的隔离将会导致并发性能大大降低,不可取;

方法2代码量多,但是基本不用修改别处代码,风险小;

方案3代码量少,只需要修改消费者的处理逻辑即可,在不熟悉业务的前提下风险大。

综上,方案3是最优的解决方案。

总结:数据库的更新,最后只更新本次更新的字段,否则会造成不必要的问题;

猜你喜欢

转载自blog.csdn.net/tony_java_2017/article/details/84036490