Redis-逻辑查询详情讲解

1、RedisData 实体类

复制代码
@Data
public class RedisData {
    private LocalDateTime expireTime; // 逻辑过期时间
    private Object data;              // 真实数据
}

2、逻辑过期查询

复制代码
// 线程池:用来异步重建缓存
private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);

// 锁前缀
public static final String LOCK_SHOP_KEY = "lock:shop:";

@Override
public Shop queryWithLogicalExpire(Long id) {
    String key = CACHE_SHOP_KEY + id;

    // 1. 从Redis查缓存
    String shopJson = stringRedisTemplate.opsForValue().get(key);

    // 2. 缓存不存在,直接返回null
    if (StrUtil.isBlank(shopJson)) {
        return null;
    }

    // 3. 缓存存在,反序列化
    RedisData redisData = JSONUtil.toBean(shopJson, RedisData.class);
    Shop shop = JSONUtil.toBean((JSONObject) redisData.getData(), Shop.class);
    LocalDateTime expireTime = redisData.getExpireTime();

    // 4. 判断是否过期
    if (expireTime.isAfter(LocalDateTime.now())) {
        // 未过期,直接返回
        return shop;
    }

    // 5. 已过期,尝试获取锁
    String lockKey = LOCK_SHOP_KEY + id;
    boolean isLock = tryLock(lockKey);

    // 6. 拿到锁,开独立线程重建缓存
    if (isLock) {
        CACHE_REBUILD_EXECUTOR.submit(() -> {
            try {
                this.saveShop2Redis(id, 20L); // 缓存重建
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                unlock(lockKey); // 释放锁
            }
        });
    }

    // 7. 无论有没拿到锁,都返回旧数据
    return shop;
}

3、缓存重建方法

复制代码
private void saveShop2Redis(Long id, Long expireSeconds) {
    // 1. 查询数据库
    Shop shop = getById(id);

    // 2. 封装逻辑过期对象
    RedisData redisData = new RedisData();
    redisData.setData(shop);
    redisData.setExpireTime(LocalDateTime.now().plusSeconds(expireSeconds));

    // 3. 写入Redis
    stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(redisData));
}

4、分布式锁

复制代码
private boolean tryLock(String key) {
    Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
    return BooleanUtil.isTrue(flag);
}

private void unlock(String key) {
    stringRedisTemplate.delete(key);
}
相关推荐
lUie INGA2 小时前
在2023idea中如何创建SpringBoot
java·spring boot·后端
小糖学代码2 小时前
LLM系列:1.python入门:15.JSON 数据处理与操作
开发语言·python·json·aigc
handler012 小时前
从源码到二进制:深度拆解 Linux 下 C 程序的编译与链接全流程
linux·c语言·开发语言·c++·笔记·学习
geBR OTTE2 小时前
SpringBoot中整合ONLYOFFICE在线编辑
java·spring boot·后端
Porunarufu2 小时前
博客系统UI自动化测试报告
java
小白学大数据3 小时前
现代Python爬虫开发范式:基于Asyncio的高可用架构实战
开发语言·爬虫·python·架构
渔舟小调3 小时前
P19 | 前端加密通信层 pikachuNetwork.js 完整实现
开发语言·前端·javascript
不爱吃炸鸡柳3 小时前
数据结构精讲:树 → 二叉树 → 堆 从入门到实战
开发语言·数据结构
网络安全许木3 小时前
自学渗透测试第21天(基础命令复盘与DVWA熟悉)
开发语言·网络安全·渗透测试·php
t***5443 小时前
如何在Dev-C++中使用Clang编译器
开发语言·c++