分布式锁的演进:
分布式锁演进——阶段1
分布式锁演进——阶段2
分布式锁演进——阶段3
分布式锁演进——阶段4
分布式锁演进——最终形态
java源代码:
private Map<Long,List<Category2Level>> getCategorysJsonFromDBWithRedisLock() {
final String LOCK_KEY = "lock";
// 生成每个线程各自的的唯一表示,区分lock值
String uuid = UUID.randomUUID().toString();
// 取redis中占坑,其他的线程就只能等待、(set lock 123 EX 300 NX),这边的过期时间和加锁一起设置,保证原子性
Boolean lock = redisTemplate.opsForValue().setIfAbsent(LOCK_KEY, uuid, 300, TimeUnit.SECONDS);
// 当前一个成功占坑
if(lock) {
System.out.println("获取分布式锁成功");
Map<Long, List<Category2Level>> datasFromDB = null;
try {
// 查询缓存
String s = redisTemplate.opsForValue().get(CATEGORY_JSON_KEY);
// 缓存中没有
if (StringUtils.isEmpty(s)){
// System.out.println("查询数据库");
// getDatasFromDB();查询数据库的逻辑
datasFromDB = getDatasFromDB();
// 在redis缓存中存数据 在锁结束时保存到缓存中
redisTemplate.opsForValue().set(CATEGORY_JSON_KEY,JSON.toJSONString(datasFromDB),1, TimeUnit.DAYS);
}
datasFromDB = JSON.parseObject(s, new TypeReference<Map<Long, List<Category2Level>>>() {
});
return datasFromDB;
}catch (Exception e){
System.out.println("业务逻辑出现异常");
}finally {
// 通过lua脚本删除锁
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
redisTemplate.execute(new DefaultRedisScript<Long>(script,Long.class), Arrays.asList(LOCK_KEY), uuid);
}
return datasFromDB;
} else {
System.out.println("获取分布式锁失败,等待重试");
// 加锁失败。。。重试
// 休眠100ms重试
try {
Thread.sleep(200);
}catch (Exception e){}
return getCategorysJsonFromDBWithRedisLock();// 自旋的方式重试
}
}
主要是用了redis当中set命令:
SET key value [EX seconds] [PX milliseconds] [NX|XX]
PX milliseconds – 设置键key的过期时间,单位时毫秒
NX – 只有键key不存在的时候才会设置key的值
这时可以引入Redission