多级缓冲-监听Canal

发布于:2023-09-22 ⋅ 阅读:(83) ⋅ 点赞:(0)

请添加图片描述
个人名片:

博主酒徒ᝰ.
个人简介沉醉在酒中,借着一股酒劲,去拼搏一个未来。
本篇励志三人行,必有我师焉。

请添加图片描述
本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》,SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式

【SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 点击观看

五、缓存同步

3. 监听Canal

Canal提供了各种语言的客户端,当Canal监听到binlog变化时,会通知Canal的客户端。

我们可以利用Canal提供的Java客户端,监听Canal通知消息。当收到变化的消息时,完成对缓存的更新。

不过这里我们会使用GitHub上的第三方开源的canal-starter客户端。地址:https://github.com/NormanGyllenhaal/canal-client

与SpringBoot完美整合,自动装配,比官方客户端要简单好用很多。

  1. 引入依赖:
<dependency>
    <groupId>top.javatool</groupId>
    <artifactId>canal-spring-boot-starter</artifactId>
    <version>1.2.1-RELEASE</version>
</dependency>
  1. 编写配置:
canal:
  destination: heima # canal的集群名字,要与安装canal时设置的名称一致
  server: 192.168.179.128:11111 # canal服务地址
  1. 修改Item实体类

通过@Id、@Column、等注解完成Item与数据库表字段的映射:

package com.heima.item.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;

import javax.persistence.Column;
import java.util.Date;

@Data //自动生成getter, setter, toString等方法
@TableName("tb_item") //对应的数据库表名
public class Item {
    @TableId(type = IdType.AUTO)
    @Id //主键
    private Long id;//商品id
    @Column(name = "name") //对应数据库表中的name属性
    private String name;//商品名称
    private String title;//商品标题
    private Long price;//价格(分)
    private String image;//商品图片
    private String category;//分类名称
    private String brand;//品牌名称
    private String spec;//规格
    private Integer status;//商品状态 1-正常,2-下架
    private Date createTime;//创建时间
    private Date updateTime;//更新时间
    @TableField(exist = false) //该字段在数据库表item中不存在
    @Transient //该字段不需要持久化到数据库
    private Integer stock;
    @TableField(exist = false)
    @Transient
    private Integer sold;
}
  1. 编写监听器

通过实现EntryHandler<T>接口编写监听器,监听Canal消息。注意两点:

  • 实现类通过@CanalTable("tb_item")指定监听的表信息
  • EntryHandler的泛型是与表对应的实体类

在Redis中操作类RedisHandler中添加Redis中增加和删除操作:

/**
 * 新增数据
 * @param item
 */
public void saveItem(Item item) {
    try {
        String json = MAPPER.writeValueAsString(item);
        redisTemplate.opsForValue().set("item:id:" + item.getId(), json);
    } catch (JsonProcessingException e) {
        throw new RuntimeException(e);
    }
}

/**
 * 删除数据
 * @param id
 */
public void deleteById(Long id) {
    redisTemplate.delete("item:id:" + id);
}

编写监听器

package com.heima.item.canal;

import com.github.benmanes.caffeine.cache.Cache;
import com.heima.item.config.RedisHandler;
import com.heima.item.pojo.Item;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.javatool.canal.client.annotation.CanalTable;
import top.javatool.canal.client.handler.EntryHandler;

@CanalTable("tb_item") //监听tb_item表
@Component
public class ItemHandler implements EntryHandler<Item> {
    @Autowired
    private RedisHandler redisHandler;
    @Autowired
    private Cache<Long, Item> itemCache;


    @Override
    public void insert(Item item) {
        //写数据到JVM进程缓存
        itemCache.put(item.getId(), item);
        //写数据到Redis
        redisHandler.saveItem(item);
    }

    @Override
    public void update(Item before, Item after) {
        itemCache.put(after.getId(), after);
        redisHandler.saveItem(after);
    }

    @Override
    public void delete(Item item) {
        //删除JVM进程缓存中的数据
        itemCache.invalidate(item.getId());
        //删除Redis中的数据
        redisHandler.deleteById(item.getId());
    }
}

重启项目:

访问:
http://localhost:8081/item/10003
在这里插入图片描述
访问:
http://localhost:8081/
在这里插入图片描述
修改ID为10003的商品信息
在这里插入图片描述
刷新第一个访问的页面,修改同步完成
在这里插入图片描述
查看Redis,也完成了修改
在这里插入图片描述

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到