rocketmq分布式事物消息

本文介绍了RocketMQ的分布式事务消息实现,包括生产者和消费者的代码实现,以及不同方式的详细步骤,如默认方式和自定义方式。同时,提到了版本兼容性和Header的使用。

分布式事物流程图

在这里插入图片描述

代码实现

rocketmq分布式事物消息 - 生产者

这里的版本借助maven helper插件,我们使用的rocketmq是4.4版本的,因此maven引入的依赖去插件里查看版本对应

  • pom.xml
<dependency>
     <groupId>org.apache.rocketmq</groupId>
     <artifactId>rocketmq-spring-boot-starter</artifactId>
     <version>2.0.2</version>
</dependency>

在这里插入图片描述

  • src/main/resources/application.yml
rocketmq:
  name-server: xxx.xxx.xxx.xxx:9876
  producer:
    group: text-group
    send-message-timeout: 300000
  • src/main/java/com/runsky/paidui/controller/TeamLeaderController.java
@Resource
private RocketMQTemplate rocketMQTemplate;

private void sendTransactionalMessage() throws Exception{
   
   

    // 2022/4/6 17:16 - mqtodo - 1 - 发送半消息
    String transactionId = UUID.randomUUID().toString();
    logger.info("------1 - sendTransactionalMessage - 发送半消息开始 :transactionId = " + transactionId + "------");
    rocketMQTemplate.sendMessageInTransaction(
            "text-half",
            MessageBuilder
                    .withPayload("分布式事物消息测试")
                    // 可以设置多个Header
                    .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
                    .setHeader("text_id", 152)
                    .build(),
            "这个arg有大用处"
    );
    logger.info("------1 - sendTransactionalMessage - 发送半消息结束 :transactionId = " + transactionId + "------");


}
  • src/main/java/com/runsky/paidui/rocketMQ/TransactionListener.java
@RocketMQTransactionListener()
public class TransactionListener implements RocketMQLocalTransactionListener {
   
   

    final static Logger logger = LoggerFactory.getLogger(TeamLeaderController.class);

    @Override
    // 2022/4/7 9:08 - mqtodo - 2 - 半消息发送成功
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
   
   

        MessageHeaders headers = msg.getHeaders();
        String transactionId = (String)headers.get(RocketMQHeaders.TRANSACTION_ID);
        Integer textId = Integer.valueOf((String)headers.get("text_id"));


        try {
   
   
            logger.info("3 - executeLocalTransaction - 执行本地事物成功 :transactionId = " + transactionId);
            // 2022/4/7 9:10 - mqtodo - 3 - 执行本地事物
            /************************************************************
             * @Author jking
             * @Date 2022/4/7 9:23
             * @Description - todo...
             * 执行本微服务的事物逻辑service方法
             * 方法(包括嵌套方法)均需要加标签 @Transactional(rollbackFor = Exception.class)
             * 方法执行成功需要写 队列log表,供 MQServer 半消息回查使用
             * 如果MQServer长期未得到半消息回复(断电等突发情况),会执行 checkLocalTransaction 方法进行回查
             * 回查的依据为 队列log表
             ************************************************************/


            // 2022/4/7 9:16 - mqtodo - 4 - 二次确认成功:提交
            return RocketMQLocalTransactionState.COMMIT;
        } catch (Exception e) {
   
   
            logger.info("3 - executeLocalTransaction - 执行本地事物失败 :transactionId = " + transactionId);

            // 2022/4/7 9:17 - mqtodo - 4 - 二次确认失败:回滚
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }


    @Override
    // 2022/4/7 9:29 - mqtodo - 5 - MQServer未收到4的半消息回复进行回查
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
   
   
        MessageHeaders headers = msg.getHeaders();
        String transactionId = (String)headers.get(RocketMQHeaders.TRANSACTION_ID);
        logger.info("5 - checkLocalTransaction - MQServer未收到4的半消息回复进行回查 :transactionId = " + transactionId);

        /************************************************************
         * @Author jking
         * @Date 2022/4/7 9:33
         * @Description - todo...
         * 6.检查本地事物状态
         * 根据 transactionId 查询 队列log表
         ************************************************************/
        // 2022/4/7 9:36 - 模拟一个 查询 队列log表 的返回值,实际生产为查询表的返回结果
        String transactionLog = "";

        if ( transactionLog != null ) {
   
   
            logger.info("7 - checkLocalTransaction -二次确认成功:提交 :transactionId = " + transactionId);

            // 2022/4/7 9:37 - mqtodo - 7 - 二次确认成功:提交
            return RocketMQLocalTransactionState.COMMIT;
        }

        logger.info("7 - checkLocalTransaction - 二次确认失败:回滚 :transactionId = " + transactionId
### MySQL 分布式事务结合 RocketMQ 的实现方案 #### 背景介绍 分布式系统的普及使得传统的单体应用逐渐向微服务架构转变。在这种背景下,分布式事务成为了一个重要的技术挑战[^4]。为了应对这一需求,许多企业采用了消息队列中间件(如 RocketMQ)来解决跨服务的数据一致性问题。 #### 方案概述 RocketMQ 提供了一种基于两阶段提交协议的分布式事务解决方案[^5]。该方案的核心思想是在生产者发送消息的第一阶段预处理数据,在第二阶段确认最终状态。以下是具体的实现细节: --- #### 技术原理 1. **第一阶段:准备阶段** 生产者发起事务请求时,首先执行本地数据库的操作,并将操作的结果记录到日志中。随后,生产者RocketMQ 发送一条半消息(Half Message),表示此消息处于待确认状态[^2]。 2. **第二阶段:提交/回滚** - 如果本地事务成功,则生产者显式调用 `commit` 方法通知 RocketMQ 将半消息转为正式消息并投递给消费者。 - 如果本地事务失败,则生产者调用 `rollback` 方法取消该消息。 - 若生产者未及时响应,RocketMQ 会触发回调机制询问生产者的事务状态,并据此决定是否提交或回滚。 3. **补偿机制** 在某些情况下,如果生产者宕机或者网络异常导致无法正常完成二阶段操作,RocketMQ 支持定时扫描未决事务列表并向生产者查询其实际状态。这一步骤能够有效防止消息丢失或重复消费[^3]。 --- #### 实现步骤 下面是一个简单的代码示例展示如何在 Java 中集成 MySQL 和 RocketMQ 来管理分布式事务: ```java // 定义事务监听器类 public class TransactionListenerImpl implements TransactionListener { @Override public LocalTransactionState executeLocalTransaction(Message msg, Object arg) { try { // 执行本地数据库更新逻辑 updateDatabase(); // 返回临时状态等待后续确认 return LocalTransactionState.UNKNOW; } catch (Exception e) { // 出错则直接回滚 return LocalTransactionState.ROLLBACK_MESSAGE; } } @Override public LocalTransactionState checkLocalTransaction(MessageExt msg) { // 查询本地事务状态以决定是提交还是回滚 boolean isCommitted = queryTransactionStatusFromDB(msg); if (isCommitted) { return LocalTransactionState.COMMIT_MESSAGE; } else { return LocalTransactionState.ROLLBACK_MESSAGE; } } private void updateDatabase() throws SQLException { Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", ""); String sql = "INSERT INTO orders(order_id, product_name) VALUES (?, ?)"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, 101); pstmt.setString(2, "Product A"); pstmt.executeUpdate(); } private boolean queryTransactionStatusFromDB(MessageExt msg) { // 假设这里通过某种方式判断事务是否已提交 return true; // 示例返回true } } ``` 上述代码展示了如何定义一个自定义的事务监听器以及如何在其内部封装本地数据库交互过程。 --- #### 最佳实践建议 1. **减少业务复杂度** 需要特别注意的是,尽管有强大的工具支持,但设计良好的分布式事务仍然依赖于清晰简洁的业务流程。复杂的多步操作往往增加出错概率,应尽量将其分解成更小粒度的任务单元[^1]。 2. **合理配置超时时间** 设置合理的最大等待时间和重试策略对于保障系统稳定性至关重要。过短的时间可能导致不必要的失败判定;而过长又会影响整体吞吐量。 3. **监控与报警** 对整个链路进行全面实时监测可以帮助快速定位潜在风险点。例如可以借助 Prometheus + Grafana 构建可视化面板跟踪各环节耗时情况及错误率变化趋势。 --- #### 总结 综上所述,采用 RocketMQ 处理涉及 MySQL 数据库变更的分布式事务是一种高效可行的方法。它不仅具备高性能特点还能很好地兼容现有基础设施环境。当然具体实施方案还需根据项目实际情况灵活调整优化参数设置等内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangjinkui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值