@Override
public Map<String, List<Catelog2Vo>> getCatalogJson() {
//1.加入缓存逻辑
String catelogJson = redisTemplate.opsForValue().get("catelogJson");
if (StringUtils.isEmpty(catelogJson)){
//2.缓存中没有,从数据库中查询数据
Map<String, List<Catelog2Vo>> catalogJsonFromDb = getCatalogJsonFromDb();
//3.查到的数据在放入缓存中 加锁情况下,这段代码可以放入锁中先存缓存在释放锁
redisTemplate.opsForValue().set("catelogJson", JSON.toJSONString(catalogJsonFromDb),1, TimeUnit.DAYS);
//返回
return catalogJsonFromDb;
}
// 返回
return JSON.parseObject(catelogJson,new TypeReference<Map<String,List<Catelog2Vo>>>(){});
}
2.加锁解决缓存击穿
/**
* 从数据库查询并封装数据
* @return
*/
public Map<String, List<Catelog2Vo>> getCatalogJsonFromDb() {
//加锁,只要同一把锁,就能锁住,需要这个锁的所有线程
// synchronized (this){} //锁住当前对象 springBoot所有的组件在容器中都是单利的
synchronized (this){
//得到锁以后,我们在去缓存中确定一次,如果没有,在去数据库中查询
//缓存中取数据
String catelogJson = redisTemplate.opsForValue().get("catelogJson");
//如果缓存中不是空的,则直接返回数据
if (!StringUtils.isEmpty(catelogJson)){
return JSON.parseObject(catelogJson,new TypeReference<Map<String,List<Catelog2Vo>>>(){});
}
//TODO 下面写查询数据逻辑
}
分布式锁逻辑
/**
* 从数据库查询并封装数据 使用Redis分布式锁
* @return
*/
public Map<String, List<Catelog2Vo>> getCatalogJsonFromDbRedisLock() {
//1.占分布式锁。去Redis中占坑 //setIfAbsent 如果Key不存在则保存
给这个key 设置过期时间 为了解决 死锁问题,设置过期时间
String uuid = UUID.randomUUID().toString();
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock",uuid , 300, TimeUnit.SECONDS);
//如果占坑成功则返回 true
if (lock) {
//加锁成功 //执行业务
Map<String, List<Catelog2Vo>> dateFromDb;
try {
dateFromDb = getDateFromDb();
} finally {
//解锁,删除坑位数据
// redisTemplate.delete("lock"); //如果锁过期消失,则有可能删除到别人的锁
// String lock1 = redisTemplate.opsForValue().get("lock");
// //如果创建锁的值和我当前锁的值相同则代表是我自己创建的锁,则删除锁
// if (uuid.equals(lock1)){
// //删除我自己的锁
// redisTemplate.delete("lock");//但是毫秒级的差, 也会出现删除到别人的锁的问题
// }
//使用redis自带了的验证的的脚本
//如果redis获取的key的值等于我指定的值调用redis 的删除方法把这个key删除掉,如果成功返回1否则返回0
String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
" return redis.call(\"del\",KEYS[1])\n" +
"else\n" +
" return 0\n" +
"end";
//删除锁
Integer lock1 = redisTemplate.execute(new DefaultRedisScript<Integer>(
script, Integer.class)
, Arrays.asList("lock")
, uuid);
}
return dateFromDb;
} else {
//加锁失败...重试
//重试次数太高 休眠100ms重试
return getCatalogJsonFromDbRedisLock(); //自旋的方式
}
}