美文网首页springjs css html
Spring在声明式事务中使用MQ产生的问题

Spring在声明式事务中使用MQ产生的问题

作者: AC编程 | 来源:发表于2023-02-08 11:02 被阅读0次

一、问题描述

在member服务调用updateMember()方法修改用户信息,该接口标注了声明式事务@Transactional,同时,在updateMember()方法里修改完用户数据后,发送了MQ通知,ES服务通过memberId取用户数据同步用户数据到ES库。

问题是:在发送MQ后,修改用户的事务还未提交(updateMember()方法还未结束),MQ有可能先于事务提交前到达,也可能在事务提交后到达,如果MQ先到达,MQ消费那里取到的用户数据就会是旧的,导致数据不一致。

二、伪代码

@Service
public class MemberServiceImpl {

    @Resource
    private MemberDao memberDao;

    @Resource
    private MemberMqSend memberMqSend;

    @Transactional(rollbackFor = Exception.class)
    public void updateMember(Member member) {
        member.setMemberName("AC");
        memberDao.update(member);

        //事务还未提交,MQ有可能先于事务提交前到达,也可能在事务提交后到达,如果MQ先到达,MQ消费那里取到的用户数据就会是旧的
        memberMqSend.sendMq(member.getId(), "UPDATE");
    }
}


@Slf4j
@Service
@RocketMQMessageListener(topic = "member",consumerGroup = "memberEs",messageModel = MessageModel.CLUSTERING)
public class MemberEsSynComponent implements RocketMQListener<MessageExt> {

    @Resource
    private MemberDao memberDao;

    @Resource
    private MemberEsDao memberEsDao;

    @Override
    public void onMessage(MessageExt message) {
        UpdateMemberMsg msg = JSONObject.parseObject(message.getBody(), UpdateMemberMsg.class);
        if (!"UPDATE".equals(msg.getAction())) {
            return;
        }

        Member member = memberDao.findById(msg.getMemberId());

        //更新ES里的Member数据,MQ可能先到达,事务还未提交,所以此处可能取到的是旧的数据
        memberEsDao.update(member);
    }
}

三、解决方案

将声明式事务改成手动事务,伪代码如下:

@Service
public class MemberServiceImpl {

    @Resource
    private MemberDao memberDao;

    @Resource
    private MemberMqSend memberMqSend;

    @Resource
    private TransactionTemplate template;
    
    public void updateMember(Member member) {
        member.setMemberName("AC");

        template.execute((TransactionCallback<Object>) transactionStatus -> {
            //手动提交事务
            memberDao.update(member);
        });
        
        //修改member的事务已提交,再发送MQ,MQ消费端再取用户数据就会是新的
        memberMqSend.sendMq(member.getId(), "UPDATE");
    }
}

相关文章

  • Spring Boot开启声明式事务

    Spring Boot开启声明式事务 在以前早期的Spring使用xml方式的时候,配置声明式事务通常用xml方式...

  • Spring事务管理机制(转载)

    Spring事务机制主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,...

  • ☆Spring 事务机制详解

    Spring事务机制主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,...

  • Spring事务

    基础概念 ​ Spring中事务支持编程式事务和声明式事务。编程式事务由使用者自行编码控制事务;声明式事务则是...

  • spring 声明式事务管理

    本节阐述在事务相关的问题上,Spring框架的声明式事务管理的内部工作原理。 关于Spring框架的声明式事务支持...

  • spring事务(二) 声明式事务

    spring事务(二) 声明式事务 知识导读 声明式事务是对编程式事务的包装 声明式事务通过使用AOP来实现,注册...

  • Spring事务

    Spring事务使用 spring事物配置,声明式事务管理和基于@Transactional注解的使用spring...

  • Spring事务的浅析

    1. 事务的使用 Spring中的事务有以下几种使用方式 编程式事务; 使用XML配置声明式事务; 使用注解配置声...

  • Spring事务

    Spring 事务 分类 Spring可以支持编程式事务和声明式事务。 编程式事务 实现 Spring使用事务管理...

  • Spring的事务传播行为

    前言 Spring同时支持编程事务策略和声明式事务策略,通常都推荐采用声明式事务策略。使用声明式事务策略的优势十分...

网友评论

    本文标题:Spring在声明式事务中使用MQ产生的问题

    本文链接:https://www.haomeiwen.com/subject/pflqkdtx.html