首先,击穿指的就是 在某件商品参加秒杀这种对一个key大流量的进行访问时(当然是redis了),忽然,这个key过期了,你的DB必崩!
如何解决?
使用互斥锁!思路就是自定义一个key value,使用 set NX px 1000 (1秒)
语句,当redis中的key过期了也不用怕怕了。他也打不死你的DB,因为你在获取DB前,先进行了
String lockKey = jedis.set(skuLockKey, "OK", "NX", "PX", ManageConst.SKULOCK_EXPIRE_PX);
//set sku:1001:info ok nx px 10000
// k 随意的v 十秒
if ("OK".equals(lockKey)){
System.out.println("获取锁!");
到这里!别的线程就不会进来了!!!
进来的这个进行,获取DB然后 爱放回reids OK了!
@Override
public SkuInfo getSkuInfo(String skuId) {
SkuInfo skuInfo = null;
try{
Jedis jedis = redisUtil.getJedis();
// 定义key
String skuInfoKey = ManageConst.SKUKEY_PREFIX+skuId+ManageConst.SKUKEY_SUFFIX; //key= sku:skuId:info
String skuJson = jedis.get(skuInfoKey);
if (skuJson==null || skuJson.length()==0){
// 没有数据 ,需要加锁!取出完数据,还要放入缓存中,下次直接从缓存中取得即可!
System.out.println("没有命中缓存");
// 定义key user:userId::lock
String skuLockKey=ManageConst.SKUKEY_PREFIX+skuId+ManageConst.SKULOCK_SUFFIX;
// 生成锁
String lockKey = jedis.set(skuLockKey, "OK", "NX", "PX", ManageConst.SKULOCK_EXPIRE_PX);
//set sku:1001:info ok nx px 10000
// k 随意的v 十秒
if ("OK".equals(lockKey)){
System.out.println("获取锁!");
// 从数据库中取得数据
skuInfo = getSkuInfoDB(skuId);
// 将是数据放入缓存
// 将对象转换成字符串
String skuRedisStr = JSON.toJSONString(skuInfo);
jedis.setex(skuInfoKey,ManageConst.SKUKEY_TIMEOUT,skuRedisStr);
//保证每次一个用户用完,都更新到redis
jedis.close();
return skuInfo;
}else {
System.out.println("等待!");
// 等待
Thread.sleep(1000);
// 自旋
return getSkuInfo(skuId);
}
}else{
// 有数据
skuInfo = JSON.parseObject(skuJson, SkuInfo.class);
jedis.close();
return skuInfo;
}
}catch (Exception e){
e.printStackTrace();
}
// 从数据库返回数据
return getSkuInfoDB(skuId);
}