黑马点评19——多级缓存-缓存同步

文章目录

在多级缓存中的数据一致性问题,也就是缓存同步的问题

数据同步策略


要是使用消息队列的方式,我们还需要修改代码,至少需要发送一条通知吧。

canal可以监听数据库的变化,监听到数据库的变化,发送通知变更,侵入性更小。

安装Canal

canal地址: https://github.com/alibaba/canal

安装和配置参考:https://blog.csdn.net/shall_zhao/article/details/142147266

监听canal实现缓存同步

但是官方原生提供的canal客户端是比较麻烦的,我们使用第三方开源的整合了springboot的canal客户端。😍

配置好以后,canal就实现了自动装配。

java 复制代码
<dependency>
            <groupId>top.javatool</groupId>
            <artifactId>canal-spring-boot-starter</artifactId>
            <version>1.2.1-RELEASE</version>
        </dependency>
java 复制代码
canal:
  destination: heima
  server: 192.168.10.88:11111


然后去我们的Item上添加注解

java 复制代码
@Data
@TableName("tb_item")
public class Item {
    @TableId(type = IdType.AUTO)
    @Id
    private Long id;//商品id
    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)
    @Transient
    private Integer stock;
    @TableField(exist = false)
    @Transient
    private Integer sold;
}

因为我们在监听到数据库发生变动的时候,只会涉及到保存数据到redis和删除redis中的数据,我们可以把这两个函数封装到RedisHandler中,直接调用。

java 复制代码
@Component
public class RedisHandler implements InitializingBean {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private IItemService itemService;

    @Autowired
    private IItemStockService stockService;

    // spring中的默认json处理工具
    private static final ObjectMapper MAPPER = new ObjectMapper();

    // afterPropertiesSet()会在bean创建完,Autowired注入以后执行,实现缓存预热效果
    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化缓存
        // 1. 查询商品信息,我们查所有的,实际上应该查询热点数据
        List<Item> itemList = itemService.list();
        // 2. 放入缓存
        for (Item item : itemList) {
            // 2.1 item序列化为JSON
            String json = MAPPER.writeValueAsString(item);
            // 2.2 存入redis
            stringRedisTemplate.opsForValue().set("item:id:" + item.getId(), json);
        }


        // 1. 查询库存信息,
        List<ItemStock> stockList = stockService.list();
        // 2. 放入缓存
        for (ItemStock stock : stockList) {
            // 2.1 item序列化为JSON
            String json = MAPPER.writeValueAsString(stock);
            // 2.2 存入redis
            stringRedisTemplate.opsForValue().set("item:stock:id:" + stock.getId(), json);
        }
    }

    public void saveItem(Item item){
        try{
            String json = MAPPER.writeValueAsString(item);
            stringRedisTemplate.opsForValue().set("item:id:" + item.getId(), json);
        } catch (JsonProcessingException e){
            throw new RuntimeException(e);
        }
    }

    public void deleteItemById(Long id){
        stringRedisTemplate.delete("item:id:" + id);
    }
}

然后编写我们的ItemHandler,要实现EntryHandler,重写其三个方法

java 复制代码
@CanalTable("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) {
        // 写数据到JVM进程缓存
        itemCache.put(after.getId(), after);
        // 写数据到redis
        redisHandler.saveItem(after);
    }

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

数据库连接遇到问题

最后重启项目测试,但是重启的时候遇到一个小问题,关于数据库的,报错内容:"Public Key Retrieval is not allowed"。

还是因为mysql8.0以后的密码验证方式发生变化了。

mysql 8.0 默认使用 caching_sha2_password 身份验证机制 (即从原来mysql_native_password 更改为 caching_sha2_password。)

从 5.7 升级 8.0 版本的不会改变现有用户的身份验证方法,但新用户会默认使用新的 caching_sha2_password 。 客户端不支持新的加密方式。 修改用户的密码和加密方式。

方式一(在这里不建议):

在命令行模式下进入mysql,输入以下命令:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';

或者

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';

然后就可以正常连接了。

方式二:

可以去直接修改密码验证方式,但这样canal就连不上了。

所以我们采用直接在配置数据源的时候直接将属性allowPublicKeyRetrieval设置为true即可

相关推荐
一直都在5725 小时前
Redis (一)
数据库·redis·缓存
秦jh_5 小时前
【Redis】客户端使用
数据库·redis·缓存
我真会写代码6 小时前
Redis核心特性详解:事务、发布订阅与数据删除淘汰策略
java·数据库·redis
IT 行者6 小时前
LangChain4j 集成 Redis 向量存储:我踩过的坑和选型建议
java·人工智能·redis·后端
wenlonglanying6 小时前
nginx 代理 redis
运维·redis·nginx
随风,奔跑7 小时前
Redis
数据库·redis·缓存
TlYf NTLE8 小时前
redis分页查询
数据库·redis·缓存
wangjialelele8 小时前
一文读懂 Redis 持久化与事务
linux·数据库·redis·bootstrap
野犬寒鸦8 小时前
Redis复习记录Day03
服务器·redis·后端·面试·bootstrap·mybatis
大萌神Nagato8 小时前
力扣HOT100 Q146LRU缓存
算法·leetcode·缓存