Redis进阶学习
1. redis的分布式锁
1.1 分布式锁的实现理念
分布式锁是指的在分布式环境中完成多机器应用操作达到同步的效果,一般都是用redis之类的实现。
1.1.1 实现原理
1.setnx key value //如果不存在就会插入
2.expire key timeout //设置过期时间
**Note:1,2原子操作**
3.del key value //删除key,释放锁
1.2 简单实现
代码demo:
public void reduceStock(){
Boolean result = StringRedisTemplate.opsForValue().setIfAbsent(lockKey,"zzz");
//没有获取锁,直接抛错
if(!result){
return "error";
}
//做业务逻辑操作
doBiz();
//删除锁
StringRedisTemplate.delete(lockkey);
}
1.3 进阶版
上述的demo有一些明显的问题需要解决,doBiz()是一个复杂的业务逻辑可能出现很多问题。这边需要处理一下这边的异常,不然当业务报错的时候锁永远删除不了。
解决办法:
- try…catch块,把释放锁放在finally块中,一定会去释放
- 添加锁的超时时间,这样的话就能在一定时间之后释放锁了
public void reduceStock(){
Boolean result = StringRedisTemplate.opsForValue().setIfAbsent(lockKey,"zzz");
try{
//没有获取锁,直接抛错
if(!result){
return "error";
}
//做业务逻辑操作
doBiz();
}catch(Exception e){
}finally{
//删除锁
StringRedisTemplate.delete(lockkey);
}
}
1.4 终极版
上述里面还存在几个问题:
- 如果web程序突然挂掉,或者重新部署(在k8s的环境是可能发生的),这个会造成死锁
- 在doBiz()的时候操作时间比较长,导致我自己的锁不是我自己解锁的,导致锁的错误
- doBiz()操作时间过长导致,锁一直被占用
public void reduceStock(){
//获取唯一业务标识
String uuid = UUID.getValue();
//添加业务超时时间,这个根据业务定
Boolean result = StringRedisTemplate.opsForValue().setIfAbsent(lockKey,uuid,60,TimeUnits.Second);
try{
//没有获取锁,直接抛错
if(!result){
return "error";
}
//做业务逻辑操作
doBiz();
}catch(Exception e){
}finally{
String value = StringRedisTemplate.opsForValue().get(lockkey);
if(uuid.equals(value)){
//只有是自己的锁才删除锁
StringRedisTemplate.delete(lockkey);
}
}
}
2. Redission
上述文件中存在一个问题就是我们预估的业务时间可能不是很有效,需要有一个方法去续业务时间。
解决办法:
- 通过在业务中开一个子线程,用while死循环的方式或者是啥,去查询key,value键值对还存不存在,如果存在就续命,不存在就结束
- redission提供的方法即可解决。