redis分布式锁
PmsSkuInfo pmsSkuInfo = null; Jedis jedis = redisUtil.getJedis(); String skuKey = "sku:" + skuId + ":info"; String skuJson = jedis.get(skuKey); if(StringUtils.isNoneBlank(skuJson)){ pmsSkuInfo = JSON.parseObject(skuJson, PmsSkuInfo.class); }else{ //nx redis自带分布式锁,只有为空时才可以set成功 String token = UUID.randomUUID().toString(); String OK = jedis.set("sku:" + skuId + ":lock", token, "nx", "px", 10000); if(StringUtils.isNotBlank(OK) && OK.equals("OK")){ pmsSkuInfo = pmsSkuInfoMapper.selectByPrimaryKey(skuId); //mysql查询结果存入redis if(null != pmsSkuInfo){ jedis.set(skuKey, JSON.toJSONString(pmsSkuInfo)); }else{ //数据库中不存在sku //为了防止缓存穿透,将null值或者空字符串值设置给redis jedis.setex(skuKey, 60*3, JSON.toJSONString("")); } //在访问mysql后,将mysql的分布式锁释放 String lockToken = jedis.get("sku:" + skuId + ":lock"); //说明:当刚好锁过期,其他线程获取到锁,本线程删除锁时,删除了其他线程获取的锁,所以需要判断删除的锁是不是自己的锁 if(StringUtils.isNotBlank(lockToken) && lockToken.equals(token)){ //说明:在判断locktoken时刚好锁过期了,其他线程获取到锁,然后本线程把其他线程的锁删除了,所以使用lua脚本,缩短时间 //jedis.eval("lua") 可以用lua脚本,在查询到key时同时删除该key,防止高并发下发生特殊情况 jedis.del("sku:" + skuId + ":lock");//用token确认锁是自己的 } }else{ //设置失败,自旋(该线程在睡眠几秒后,重新访问) try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return getSkuById(skuId); } } jedis.close(); //sku图片集合 List<PmsSkuImage> pmsSkuImageList = pmsSkuImageMapper.selectBySkuId(skuId); pmsSkuInfo.setSkuImageList(pmsSkuImageList); return pmsSkuInfo;