SpringBoot 事务消息:解决数据库事务与RocketMQ消费顺序不一致问题
要保证事务提交后 MQ 才消费,可以使用 MQ 的事务消息功能。Spring Cloud Stream 集成了 RocketMQ 的事务消息功能,可以使用@Transactional注解和RocketMQTransactionListener来实现。
首先,在 Spring Boot 的订单方法上添加@Transactional注解,确保方法中的数据库操作在一个事务中。这样,如果方法执行成功,则事务会被提交;如果方法执行失败,则事务会被回滚。
@Transactional
public void updateOrderAndInventory() {
// 修改订单信息
// 修改库存信息
}
接下来,配置 RocketMQ 的事务消息监听器RocketMQTransactionListener。该监听器实现了 RocketMQ 的事务消息接口,可以在其中编写本地事务和消息发送逻辑。
@Component
public class MyRocketMQTransactionListener implements RocketMQLocalTransactionListener {
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
try {
// 执行本地事务(修改 ES 库存)
// 如果本地事务执行成功,则返回 COMMIT 状态,否则返回 ROLLBACK 状态
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
return RocketMQLocalTransactionState.ROLLBACK;
}
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(MessageExt msg) {
// 根据消息的状态判断本地事务的执行结果
// 如果本地事务已提交,则返回 COMMIT 状态;如果本地事务已回滚,则返回 ROLLBACK 状态
// 如果本地事务还在进行中,则返回 UNKNOWN 状态
return RocketMQLocalTransactionState.UNKNOWN;
}
}
然后,在订单方法中调用 RocketMQ 发送事务消息,将本地事务的执行结果作为消息的附加信息发送给 RocketMQ。
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Transactional
public void updateOrderAndInventory() {
// 修改订单信息
// 修改库存信息
// 发送事务消息
rocketMQTemplate.sendMessageInTransaction('topic', 'message', 'transactional-arg');
}
最后,在配置文件中添加 RocketMQ 的事务消息监听器配置。
spring:
cloud:
stream:
rocketmq:
binder:
transaction:
listener:
enable: true
这样,当订单方法执行成功并提交事务时,RocketMQ 会收到事务消息,并调用RocketMQTransactionListener的executeLocalTransaction方法执行本地事务。只有在本地事务执行成功并返回 COMMIT 状态时,RocketMQ 才会将消息发送给消费者消费,从而保证了事务提交后 MQ 才消费的顺序。如果本地事务执行失败并返回 ROLLBACK 状态,RocketMQ 会将消息进行回滚。
注意,要确保在 RocketMQ 的事务监听器中执行的本地事务和数据库事务是同一个事务,可以使用同一个数据库连接或者使用分布式事务框架(如 Seata)来管理事务。
原文地址: http://www.cveoy.top/t/topic/pb3W 著作权归作者所有。请勿转载和采集!