RocketMQ解决分布式下最终一致性事务问题

订单服务、用户服务、商品服务
1.订单服务发送事务消息

    public String create() {
        //发送half事务消息
        orderMessageSender.sendCreateOrderMsg(123L,SecurityUtils.getMemberId());
        return null;
    }


    //发送事务消息
    @Slf4j
@Component
public class OrderMessageSender {
/*
    @Value("${rocketmq.tulingmall.scheduleTopic}")
    private String scheduleTopic;

    @Value("${rocketmq.tulingmall.transGroup}")
    private String transGroup;

    @Value("${rocketmq.tulingmall.transTopic}")
    private String transTopic;*/

    @Value("${rocketmq.tulingmall.asyncOrderTopic}")
    private String asyncOrderTopic;

    private String TAG = "cancelOrder";
    private String TXTAG = "trans";
    private String ORDERTAG = "create-order";

    @Autowired
    private RocketMQTemplate rocketMQTemplate;


    /**
     * 使用事务消息机制发送订单
     * @return
     */
    public boolean sendCreateOrderMsg(Long orderId, Long memberId){
        String destination = asyncOrderTopic+":"+ORDERTAG;
        Message<String> message = MessageBuilder.withPayload(orderId+":"+memberId)
                .build();
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(destination,message,orderId);
        return SendStatus.SEND_OK == sendResult.getSendStatus();
    }


}
/**
 * 订单事务消息监听器
 */
@Slf4j
@RocketMQTransactionListener()
public class TransactionListenerImpl implements RocketMQLocalTransactionListener {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    TransactionLogService transactionLogService;
    /**
     * 回查次数可以根据订单超时事件定制,普通订单超时时间来自于oms_order_settings
     * 下单事务消息的本地事务
     * redis中记录回查的次数
     * 返回UNKNOWN状态,等待事务回查
     * 监听到发送half消息,执行本地事务
     */
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        log.info("order开始执行本地事务-------------");

        try {
            String transId = (String)msg.getHeaders().get(RocketMQHeaders.PREFIX + RocketMQHeaders.TRANSACTION_ID);
            String orderId = String.valueOf(arg);
            TransactionLog transactionLog = new TransactionLog();
            transactionLog.setTransactionId(transId);
            transactionLog.setBusiness("生成订单");
            transactionLog.setForeignKey(orderId);
            transactionLogService.insert(transactionLog);
            return RocketMQLocalTransactionState.COMMIT;
        } catch (Exception e) {
            log.error("创建rocketMQ下单事务消息失败,原因:{}",e);
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }

    /**
     * 下单事务回查,事务状态回查最大次数transactionCheckMax  默认15次,每次回查的间隔时间transactionTimeOut 默认6秒。检查10次,模拟一分钟支付时间
     * @param message
     * @return
     */
    //本地事务检查,检查本地事务是否成功
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
        //获取事务ID
        String transId = (String)message.getHeaders().get(RocketMQHeaders.PREFIX + RocketMQHeaders.TRANSACTION_ID);
        log.info("检查本地事务,事务ID:{}", transId);
        //根据事务id从日志表检索
        TransactionLog  transactionLog=transactionLogService.findByTransactionId(transId);

        if (null != transactionLog) {
            return RocketMQLocalTransactionState.COMMIT;
        }
        return  RocketMQLocalTransactionState.ROLLBACK;
    }
}
用户服务
@Slf4j
@Component
@RocketMQMessageListener(consumerGroup = "ums-group", topic = "${rocketmq.tulingmall.asyncOrderTopic}")
public class RocketMqCreateOrderReciever implements RocketMQListener<String> {



    /**
     * 延时消息,取消超时订单
     * @param message orderId:memberId
     */
    @Override
    public void onMessage(String message) {
        if(StringUtils.isEmpty(message)){
            return;
        }
        Long orderId = Long.parseLong(message.split(":")[0]);
        Long memberId = Long.parseLong(message.split(":")[1]);
        try {
            log.info("-----------------执行扣除用户积分------------");
        } catch (Exception e) {
            log.error("订单取消异常 : 还原库存失败,please check:{}",e.getMessage(),e.getCause());
            throw new RuntimeException();//抛异常出去,rocketmq会重新投递
        }
    }
}
商品服务
@Slf4j
@Component
@RocketMQMessageListener(consumerGroup = "pms-group", topic = "${rocketmq.tulingmall.asyncOrderTopic}")
public class RocketMqCreateOrderReciever implements RocketMQListener<String> {
    /**
     * 延时消息,取消超时订单
     * @param message orderId:memberId
     */
    @Override
    public void onMessage(String message) {
        if(StringUtils.isEmpty(message)){
            return;
        }
        int i=1/0;
        Long orderId = Long.parseLong(message.split(":")[0]);
        Long memberId = Long.parseLong(message.split(":")[1]);
        try {
            log.info("-----------------执行扣除库存------------");
        } catch (Exception e) {
            log.error("订单取消异常 : 还原库存失败,please check:{}",e.getMessage(),e.getCause());
            throw new RuntimeException();//抛异常出去,rocketmq会重新投递
        }
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值