java事务提交完成再继续执行

阅读: 评论:0

java事务提交完成再继续执行

java事务提交完成再继续执行

问题描述

之前遇到过一个这样的问题:在服务A里的执行一个保存数据库方法,数据保存成功后会将主键ID通过MQ发送给服务B,服务B再根据主键ID去查询保存的数据,进行其他逻辑处理。后来发现,在服务B中根据MQ发送过来的ID通过数据库偶尔会查不到数据信息。

后来通过调试才发现,是因为在服务A里的保存方法加了事务注解,保存的数据结果只有在当前方法执行完成后才会对外生效,而MQ消息则是在保存方法执行前发送的,如果服务B在服务A中保存方法执行完成前就收到了MQ消息,就会导致上述问题发生。同样,如果在MQ发送成功后,保存方法发生了异常导致事务回滚,服务B也会查不到数据或者查询到错误的数据。

问题分析

导致上述问题发生的根本原因还是因为发送MQ消息是在加了事务回滚的方法内部执行的,通过该方法保存或更新的数据只有在整个方法结束后才会对外生效,而MQ的消费者却有可能于改方法执行完成前收到消息。因此,最直接的解决办法是要将MQ消息放到事务方法结束后再执行。

但是,由于在项目中有很多处都是采用上述的这种逻辑,一个个改起来比较麻烦,最好能有一个通用的方式能够尽量少改动之前的业务逻辑代码就能解决问题。

解决方法

对于这种通用业务的问题第一个想到的解决方法就是利用AOP:拦截所有带有事务回滚注解(@Transactional)的方法,通过某种方式获取到该方法内部所有要执行的发送MQ的调用代码,让它们在事务方法执行成功后在执行。

示例代码

TransactionMessageAspect继承TransactionSynchronizationAdapter,实现对所有带有@Transactional注解方法的拦截:

TransactionInterceptorHandler:使用ThreadLocal对当前线程中要执行的发送MQ方法进行缓存

MqMessage: 发送MQ消息的封装类

将其更改为:

流程分析TransactionMessageAspect会拦截带有@Transactional注解的方法,使用TransactionInterceptorHandler.signInTransaction()标记当前方法已进入事务模式;

如果在执行事务方法的过程中,有调用MqMessage.sendMessage()方法进行传递,会先将要发送的消息逻辑封装到Callable中,并通过TransactionInterceptorHandler.addAction保存在本地线程中;

当事务提交成功并没有回滚后再通过TransactionMessageAspect.afterCompletion()方法执行保存在本地线程中要发送MQ的调用方法;

参考

本文发布于:2024-01-28 08:24:17,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17064014616091.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:事务   java
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23