1、将任意对象都可以转换为json字符串形式存入缓存
public void set(String key, Object value, Long time, TimeUnit unit){
// 需要将任意类型的对象转换为json字符串
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value),time,unit);
}
2、增加新一列:逻辑过期时间
public void setWithLogicalExpiredTime(String key, Object value, Long time, TimeUnit unit){
RedisData redisData = new RedisData();
redisData.setData(value);
redisData.setExpiredTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(redisData));
}
3、缓存穿透,参数中需要自己编写查询的函数
public <R,ID> R queryWithPassThrough(String prefix, ID id, Class<R> type, Function<ID,R> dbCallback,Long time,TimeUnit unit){
String key = prefix + id;
// 从redis中进行查询
String info = stringRedisTemplate.opsForValue().get(key);
// 查询到了直接返回
if(StrUtil.isNotBlank(info)){
return JSONUtil.toBean(info, type);
}
// 判断是否为null 或 空
if (info != null){
return null;
}
// 未查询到向数据库进行查询 交给调用者去编写
//Shop shop = getById(id);
R res = dbCallback.apply(id);
// 数据库若也未查询到 返回404 防缓存穿透加入一个空值
if(res == null){
stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES);
return null;
}
// 若查询到了将数据写入缓存
// 增加一个超时剔除
this.set(key,res,time,unit);
// 返回查询到的结果
return res;
}
4、逻辑过期的形式解决缓存击穿,里面包含了线程池,获取互斥锁,释放锁等方法
private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);
public <R,ID> R queryWithLogicalExpire(String prefix, ID id, Class<R> type, Function<ID,R> dbCallback,Long time,TimeUnit unit){
String key = prefix + id;
// 从redis中进行查询
String info = stringRedisTemplate.opsForValue().get(key);
// 没有查询到返回空
if(StrUtil.isBlank(info)){
R res = JSONUtil.toBean(info, type);
return null;
}
// 查询到获取字段 检查过期时间
// 先把json字符串反序列化为对象
RedisData redisData = JSONUtil.toBean(info, RedisData.class);
JSONObject data = (JSONObject) redisData.getData();
R res = JSONUtil.toBean(data, type);
LocalDateTime expiredTime = redisData.getExpiredTime();
// 没过期返回商品信息
if(expiredTime.isAfter(LocalDateTime.now())){
return res;
}
// 过期了尝试获取互斥锁
// 缓存重建
String lockKey = LOCK_SHOP_KEY+id;
boolean triedLock = tryLock(lockKey);
// 获取到了 开启新线程
if(triedLock){
// 开启新线程
CACHE_REBUILD_EXECUTOR.submit(() -> {
R r = dbCallback.apply(id);
this.setWithLogicalExpiredTime(key,r,time,unit);
unlock(lockKey);
});
}
// 没获取到 直接返回旧信息
return res;
}
// 加互斥锁
private boolean tryLock(String key){
Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", LOCK_SHOP_TTL, TimeUnit.SECONDS);
return BooleanUtil.isTrue(flag);
}
// 释放锁
private void unlock(String key){
stringRedisTemplate.delete(key);
}