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);
}
相关推荐
Via_Neo2 小时前
今天是周六,两天后是周几?
java·数据结构·算法
chools2 小时前
Java后端拥抱AI开发之个人学习路线 - - Spring AI【第二期】
java·人工智能·学习·spring·ai
uNke DEPH2 小时前
MySQL中常见函数
java
大鹏说大话2 小时前
Java线程池调优实战:从核心参数到避坑指南
java·开发语言
※DX3906※2 小时前
SpringBoot之旅5| 快速上手SpringAOP、深入刨析动态/静态两种代理模式
java·数据库·spring boot·后端·spring·java-ee·代理模式
lolo大魔王2 小时前
Go语言的基础语法
开发语言·后端·golang
小陈工2 小时前
Python Web开发入门(八):用户认证系统实现,给你的应用加上安全锁
开发语言·前端·数据库·python·安全·django·sqlite
铅笔侠_小龙虾2 小时前
Miniconda + Poetry 实战
开发语言·python
jwt7939279372 小时前
基于SpringBoot和Leaflet的行政区划地图掩膜效果实战
java·spring boot·后端