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);
}
相关推荐
zhangfeng11332 小时前
openclaw skills 小龙虾技能 通讯仿真 matlab skill Simulink Agentic Toolkit,通过kimi找到,mcp通讯
开发语言·matlab·openclaw·通讯仿真
Javatutouhouduan8 小时前
2026Java面试的正确打开方式!
java·高并发·java面试·java面试题·后端开发·java编程·java八股文
chao1898448 小时前
基于 SPEA2 的多目标优化算法 MATLAB 实现
开发语言·算法·matlab
JAVA面经实录9178 小时前
Java初级最终完整版学习路线图
java·spring·eclipse·maven
赏金术士8 小时前
Kotlin 习题集 · 高级篇
android·开发语言·kotlin
Cat_Rocky9 小时前
k8s-持久化存储,粗浅学习
java·学习·kubernetes
楼兰公子9 小时前
buildroot 在编译rust时裁剪平台类型数量的方法
开发语言·后端·rust
知识领航员10 小时前
蘑兔AI音乐深度实测:功能拆解、实测表现与适用场景
java·c语言·c++·人工智能·python·算法·github
吴声子夜歌10 小时前
Go——并发编程
开发语言·后端·golang
释怀°Believe10 小时前
Spring解析
java·后端·spring