Springboot-Rabbitmq消费者端执行sql异常回滚问题

新手上路,请多包涵

尊敬的大佬们:

小弟初学springboot 集成 rabbitmq,遇到了一个问题,就是关于rabbitmq消费端异常回滚问题。
比如: 我们下了一个订单,把相关业务放到rabbitmq消费端处理,现在同时需要处理2个事件,第一需要修改订单状态,第二需要修改用户的余额,在springboot里我们可以使用@Transactional可以保证以上两点同时修改才算完成,但是在rabbitmq消费端@Transactional就失效了,导致比如第一部修改状态完成,中间出现了异常,第二部修改用户余额的操作就没有进行。求解,怎么在rabbitmq消费者端实现sql执行的回滚操作。代码如下:
  @Transactional(rollbackFor = Exception.class)
    @RabbitListener(queues = Demo.DELAYED_QUEUE)
    public void delayedQueueReceiver(Map map, Message message, Channel channel) throws IOException {
        try {
        
            Test test1 = new Test();
            testMapper.insert(test1);
            L.error("插入-" + test1.getDid());

            int i = 1 / 0; //处理出现异常

            Test test2 = new Test();
            testMapper.insert(test2);
            L.error("插入-" + test2.getDid());

        } catch (Exception e) {
            L.error("发生了异常" + e.getMessage());
            e.printStackTrace();
        }


        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

以上代码,导致test2失败,test1成功,我希望如果test2失败,哪test1也不执行。

阅读 3k
2 个回答

这个问题涉及到Spring声明式事务的实现原理,简略的说,Spring会通过AOP机制为被@Transactional注解标记的类或方法生成代理,在代理中完成事务的管控(提交、回滚等)等工作,以Spring官方文档的一张图来表示如下:
企业微信截图_16563173799586.png
上图中,事务的回滚是发生在Transaction Advisor中的,如果我们在自己的方法(Target Method)中就把异常给吞掉,那Transaction Advisor自然无法识别到异常,更遑论要正确回滚事务了。

所以这个问题可以有两个解决方案:

  1. 不要吞掉执行过程中的异常,去掉try catch或者catch后再重新throw出去
  2. 将同一事务的操作都封装到另外一个Service的方法中,在消费时,调用封装好的方法

参考资料
https://docs.spring.io/spring...

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏