实现elasticsearch和数据库的数据同步

1. 数据同步

elasticsearch中的酒店数据来自于mysql数据库,因此mysql数据发生改变时,elasticsearch也必须跟着改变,这个就是elasticsearch与mysql之间的数据同步

1.1. 思路分析

常见的数据同步方案有三种:

  • 同步调用

  • 异步通知

  • 监听binlog

1.2. 同步调用

方案一:同步调用:

基本步骤如下:

  • hotel-demo对外提供接口,用来修改elasticsearch中的数据

  • 酒店管理服务在完成数据库操作后,直接调用hotel-demo提供的接口

优缺点:

  • 优点:实现简单,粗暴

  • 缺点:业务耦合度高

1.3. 异步通知

方案二:异步通知:

流程如下:

  • hotel-admin对mysql数据库数据完成增、删、改后,发送MQ消息

  • hotel-demo监听MQ,接收到消息后完成elasticsearch数据修改

优缺点:

  • 优点:低耦合,实现难度一般

  • 缺点:依赖mq的可靠性

1.4. 监听binlog

方案三:监听binlog:

流程如下:

  • 给mysql开启binlog功能 (平时默认关闭)

  • mysql完成增、删、改操作都会记录在binlog中

  • hotel-demo基于canal监听binlog变化,实时更新elasticsearch中的内容

1.5. 总结

实现elasticsearch和数据库数据同步一般有以下三种方法:

方式一:同步调用

  • 优点:实现简单,粗暴

  • 缺点:业务耦合度高

方式二:异步通知

  • 优点:低耦合,实现难度一般

  • 缺点:依赖mq的可靠性

方式三:监听binlog

  • 优点:完全解除服务间耦合

  • 缺点:开启binlog增加数据库负担、实现复杂度高

2. 实现数据同步

2.1. 思路

利用hotel-admin项目作为酒店管理的微服务。当酒店数据发生增、删、改时,要求对elasticsearch中数据也要完成相同操作。

步骤:

  • 声明exchange、queue、RoutingKey

  • 在hotel-admin中的增、删、改业务中完成消息发送

  • 在hotel-demo中完成消息监听,并更新elasticsearch中数据

  • 启动并测试数据同步功能

2.2. hotel-admin

其中包含了酒店的CRUD功能:

2.3. 声明交换机和队列

MQ结构如图:

2.3.1. 引入依赖

在hotel-admin、hotel-demo中引入rabbitmq的依赖:

<!--amqp-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2.3.2. 声明交换机名称

在hotel-admin和hotel-demo中的cn.itcast.hotel.constatnts包下新建一个类MqConstants

代码如下:

java 复制代码
public class MqConstants {
    //交换机名称
    public final static String HOTEL_EXCHANGE = "hotel.topic";

    //监听新增和修改的队列
    public final static String HOTEL_INSERT_QUEUE = "hotel.insert.queue";
    //监听删除的队列
    public final static String HOTEL_DELETE_QUEUE = "hotel.delete.queue";

    //新增或修改的RoutingKey
    public final static String HOTEL_INSERT_KEY = "hotel.insert";
    //删除的RoutingKey
    public final static String HOTEL_DELETE_KEY = "hotel.delete";

}

2.3.3. 声明队列交换机

在hotel-demo中建一个config包,包下建一个配置类MqConfig,声明队列、交换机:

java 复制代码
package cn.itcast.hotel.config;

import cn.itcast.hotel.constants.MqConstants;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 基于Bean的形式生成交换机和队列
 * 以及将他们绑定
 */
@Configuration
public class MqConfig {

    //生成topic交换机
    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange(MqConstants.HOTEL_EXCHANGE,true,false);
    }

    //insert队列
    @Bean
    public Queue insertQueue(){
        return new Queue(MqConstants.HOTEL_INSERT_QUEUE,true);
    }

    //delete队列
    @Bean
    public Queue deleteQueue(){
        return new Queue(MqConstants.HOTEL_DELETE_QUEUE,true);
    }

    //绑定insert队列和交换机
    @Bean
    public Binding insertQueueBinding(){
        return BindingBuilder.bind(insertQueue()).to(topicExchange()).with(MqConstants.HOTEL_INSERT_KEY);
    }

    //绑定delete队列和交换机
    @Bean
    public Binding deleteQueueBinding(){
        return BindingBuilder.bind(deleteQueue()).to(topicExchange()).with(MqConstants.HOTEL_DELETE_KEY);
    }

}

2.4. 发送MQ消息

在hotel-admin中的增、删、改业务中分别发送MQ消息:

2.5. 接受MQ消息

hotel-demo接收到MQ消息要做的事情包括:

  • 新增消息:根据传递的hotel的id查询hotel信息,然后新增一条数据到索引库

  • 删除消息:根据传递的hotel的id删除索引库中的一条数据

2.5.1. 添加新增、删除业务

首先在hotel-demo的cn.itcast.hotel.service包下的IHotelService中新增新增、删除业务

java 复制代码
void deleteById(Long id);

void insertById(Long id);

2.5.2. 实现业务

java 复制代码
@Override
public void deleteById(Long id) {
    try {
        // 1.准备Request
        DeleteRequest request = new DeleteRequest("hotel", id.toString());
        // 2.发送请求
        client.delete(request, RequestOptions.DEFAULT);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

@Override
public void insertById(Long id) {
    try {
        // 0.根据id查询酒店数据
        Hotel hotel = getById(id);
        // 转换为文档类型
        HotelDoc hotelDoc = new HotelDoc(hotel);

        // 1.准备Request对象
        IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());
        // 2.准备Json文档
        request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);
        // 3.发送请求
        client.index(request, RequestOptions.DEFAULT);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

2.5.3. 编写监听器

在hotel-demo中的cn.itcast.hotel.mq包新增一个类:

java 复制代码
package cn.itcast.hotel.mq;

import cn.itcast.hotel.constants.MqConstants;
import cn.itcast.hotel.service.IHotelService;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HotelListener {

    @Autowired
    private IHotelService hotelService;

    /**
     * 监听酒店新增或修改的业务
     * @param id 酒店id
     */
    @RabbitListener(queues = MqConstants.HOTEL_INSERT_QUEUE)
    public void listenHotelInsertOrUpdate(Long id){
        hotelService.insertById(id);
    }

    /**
     * 监听酒店删除的业务
     * @param id 酒店id
     */
    @RabbitListener(queues = MqConstants.HOTEL_DELETE_QUEUE)
    public void listenHotelDelete(Long id){
        hotelService.deleteById(id);
    }
}

这样,就可以实现elasticsearch和Mysql数据库的数据同步了!

3. 测试

tips:记得开启RabbitMQ

我们来测试一下:

3.1 启动hotel-demo和hotel-admin服务:

访问浏览器:

我们看到"上海虹口三至喜来登酒店" 的价格是 1899

我们去酒店管理端修改一下:

3.2. 修改操作

打开酒店管理端,然后找到该酒店,进行修改:

我们将价格改为1898:

3.3.查看结果

此时可以先打开RabbitMQ的控制台,可以看见确实有消息发送了:

我们再打开前端页面,刷新查看:

"上海虹口三至喜来登酒店" 价格确实变成了1898

在此期间,我们并未对elasticsearch进行手动修改数据,说明我们确实完成了基于MQ的elasticsearch和mysql数据库之间数据的消息同步!

相关推荐
夜泉_ly2 小时前
MySQL -安装与初识
数据库·mysql
qq_529835353 小时前
对计算机中缓存的理解和使用Redis作为缓存
数据库·redis·缓存
月光水岸New5 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6755 小时前
数据库基础1
数据库
我爱松子鱼5 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo6 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser7 小时前
【SQL】多表查询案例
数据库·sql
Galeoto7 小时前
how to export a table in sqlite, and import into another
数据库·sqlite
人间打气筒(Ada)7 小时前
MySQL主从架构
服务器·数据库·mysql
leegong231117 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql