乐优商城(九)数据同步

本文讲述了如何通过SpringBoot集成RabbitMQ解决项目中微服务间的数据同步问题,重点介绍商品数据更新时如何触发搜索和详情微服务的更新操作。
摘要由CSDN通过智能技术生成

1. 项目问题分析

现在项目中有三个独立的微服务:

  • 商品微服务:原始数据保存在 MySQL 中,从 MySQL 中增删改查商品数据。
  • 搜索微服务:原始数据保存在 ES 的索引库中,从 ES 中查询商品数据。
  • 商品详情微服务:做了页面静态化,静态页面的商品数据不会随着数据库发生变化。

假如我在商品微服务中,修改了商品的数据,也就是 MySQL 中数据发生了改变。但搜索微服务查询到的数据还是原来的,商品详情微服务的生成的静态页面也没有发生改变,这样显然不对。我们需要实现数据的同步,让搜索微服务和商品详情微服务的商品也发生修改。

我们使用消息队列技术(RabbitMQ)来实现数据同步:

2. 项目改造

接下来,我们就改造项目,实现搜索微服务和商品详情微服务的数据同步。

2.1 改造思路

生产者:商品微服务

  • 什么时候发送消息?

    当商品微服务对商品进行增、删、改的操作时候,就发送一条消息。

  • 发送什么内容?

    我们发送商品 id,其它微服务可以根据 id 查询自己需要的信息。

消费者:搜索微服务和商品详情微服务

接收消息后如何处理?

  • 搜索微服务:
    • 增/改:添加新的数据到索引库
    • 删:删除索引库数据
  • 商品详情微服务:
    • 增/改:创建新的静态页
    • 删:删除原来的静态页

2.2 商品微服务发送消息

在 leyou-item-service 中实现商品微服务发送消息。

2.2.1 引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.2.2 配置文件

在 application.yaml 中添加 RabbitMQ 的配置:

spring:
  rabbitmq:
    host: 127.0.0.1
    username: leyou
    password: leyou
    virtual-host: /leyou
    template:
      exchange: leyou.item.exchange
    publisher-confirms: true
  • template:有关 AmqpTemplate 的配置
    • exchange:缺省的交换机名称,此处配置后,发送消息如果不指定交换机就会使用这个
  • publisher-confirms:生产者确认机制,确保消息会正确发送,如果发送失败会有错误回执,从而触发重试
2.2.3 改造 SpuService
  1. 注入 AmpqTemplate 模板

@Autowired
private AmqpTemplate amqpTemplate;

编写发送消息方法

/**
 * 发送消息
 * @param id 商品 id
 * @param type
 */
private void sendMessage(Long id, String type){
    try {
        this.amqpTemplate.convertAndSend("item." + type, id);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

在新增方法中,调用发送消息方法

在修改方法中,调用发送消息方法

在这里插入图片描述

2.3 搜索微服务接收消息

在 leyou-search 中实现搜索微服务接收消息。

2.3.1 引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.3.2 配置文件
spring:
  rabbitmq:
    host: 127.0.0.1
    username: leyou
    password: leyou
    virtual-host: /leyou
2.3.3 编写监听器

@Component
public class GoodsListener {

    @Autowired
    private SearchService searchService;

    /**
     * 处理 insert 和 update 的消息
     *
     * @param id
     * @throws Exception
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "leyou.create.index.queue", durable = "true"),
            exchange = @Exchange(
                    value = "leyou.item.exchange",
                    ignoreDeclarationExceptions = "true",
                    type = ExchangeTypes.TOPIC),
            key = {"item.insert", "item.update"}))
    public void listenCreate(Long id) throws Exception {
        if (id == null) {
            return;
        }
        // 创建或更新索引
        this.searchService.createIndex(id);
    }

    /**
     * 处理 delete 的消息
     *
     * @param id
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "leyou.delete.index.queue", durable = "true"),
            exchange = @Exchange(
                    value = "leyou.item.exchange",
                    ignoreDeclarationExceptions = "true",
                    type = ExchangeTypes.TOPIC),
            key = "item.delete"))
    public void listenDelete(Long id) {
        if (id == null) {
            return;
        }
        // 删除索引
        this.searchService.deleteIndex(id);
    }
}
2.3.4 编写创建和删除索引方法

在 SearchService 中添加创建和删除索引方法:

/**
 * 创建索引
 *
 * @param id
 * @throws IOException
 */
public void createIndex(Long id) throws IOException {
    Spu spu = this.spuClient.querySpuById(id);
    // 构建商品
    Goods goods = this.buildGoods(spu);

    // 保存数据到索引库
    this.goodsRepository.save(goods);
}
/**
 * 删除索引
 *
 * @param id
 */
public void deleteIndex(Long id) {
    this.goodsRepository.deleteById(id);
}

2.4 商品详情微服务接收消息

在 leyou-goods-web 中实现商品详情微服务接收消息。

2.4.1 引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.4.2 配置文件
spring:
  rabbitmq:
    host: 127.0.0.1
    username: leyou
    password: leyou
    virtual-host: /leyou
2.4.3 编写监听器

在这里插入图片描述

@Component
public class GoodsListener {

    @Autowired
    private GoodsHtmlService goodsHtmlService;

    /**
     * 处理 insert 和 update 的消息
     *
     * @param id
     * @throws Exception
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "leyou.create.web.queue", durable = "true"),
            exchange = @Exchange(
                    value = "leyou.item.exchange",
                    ignoreDeclarationExceptions = "true",
                    type = ExchangeTypes.TOPIC),
            key = {"item.insert", "item.update"}))
    public void listenCreate(Long id) throws Exception {
        if (id == null) {
            return;
        }
        // 创建页面
        goodsHtmlService.createHtml(id);
    }

    /**
     * 处理 delete 的消息
     *
     * @param id
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "leyou.delete.web.queue", durable = "true"),
            exchange = @Exchange(
                    value = "leyou.item.exchange",
                    ignoreDeclarationExceptions = "true",
                    type = ExchangeTypes.TOPIC),
            key = "item.delete"))
    public void listenDelete(Long id) {
        if (id == null) {
            return;
        }
        // 删除页面
        goodsHtmlService.deleteHtml(id);
    }
}
2.4.4 添加删除页面方法

在 GoodsHtmlService 中 添加删除页面方法

/**
 * 删除 HTML 页面
 * @param id
 */
public void deleteHtml(Long id) {
    File file = new File("D:\\nginx-1.14.0\\html\\item\\" + id + ".html");
    file.deleteOnExit();
}

3. 测试

  1. 启动微服务

打开 RabbitMQ 管理界面,交换机和队列都已将创建好了

启动后台管理系统和门户系统

查看搜索商品页和商品详情页

进入后台管理系统,修改商品价格为 4999

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值