开发者社区> 问答> 正文

路过的讨论一下:纠结MQ是在放service事务外还是事务内? 400 报错

路过的讨论一下:纠结MQ是在放service事务外还是事务内? 400 报错

如一方法

@Transactional

XXService

public void xxx(){
        a();
        b();
        mq();
}

如果mq放在事务内,a()和b()事务提交时间可能比较长,mq()发出去后,消费者可能在消费消息时,a,b方法还没提交完毕(等事务吧),这时数据就会乱了。

改成下面的


YYYController

public void hello(){
        
       xxxService.xxx();// 里有a,b方法
       mq();
}

如果xxx()方法执行成功了,mq()失败了,那么mq消息发不了,消息丢失。

有什么好的办法不?各位大佬

展开
收起
爱吃鱼的程序员 2020-06-01 14:36:12 738 0
1 条回答
写回答
取消 提交回答
  • https://developer.aliyun.com/profile/5yerqm5bn5yqg?spm=a2c6h.12873639.0.0.6eae304abcjaIB

    一般是放在事务之外. 主要原因是, 很多时候DB事务提交 有可能会撞中各种问题而回滚. 至于MQ,一般来说,都做了高可用和本地的异步提交.

    ######

    你mq()成功了,也只代表消息发出去了,消息的消费者有没有正常收到,有没有正常处理还是个未知数,所以我感觉mq()反正都是没办法与前面的两个方法做到强一致的,不如放事务外面。不过具体还得结合业务来看。

    ######

    1. 可以使用spring提供的链式事务管理器 (ChainedTransactionManager) 把多个资源操作在一个事务中提交(假如 事务在提交过程中 db 或mq 服务挂掉时,这种方式会出问题 。涉及到多个资源属于分布式数据一致性问题) 

    2.考虑使用Rocketmq 的事务消息 (有消息回查机制)

    ######

    消息补偿+幂等

    ######

    一般的业务建议放在service层事务外,mq内部一般会有处理投递失败的处理机制,实在不行可以捕捉mq的异常,失败了可以做重试、日志记录等补偿操作,达到最终一致性就可以了

    ######

    也可以将a(),b()设置成独立事务,先提交,然后mq()。

    ######

    多谢各位的说法

    2020-06-01 14:36:13
    赞同 展开评论 打赏
问答分类:
问答标签:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
RocketMQ Client-GO 介绍 立即下载
RocketMQ Prometheus Exporter 打造定制化 DevOps 平台 立即下载
基于 RocketMQ Prometheus Exporter 打造定制化 DevOps 平台 立即下载