前言:随着行业的发展和微服务分布式的兴起,由此会引来并发问题,如果单服务单机情况可以不去考虑分布式锁。
但是,现在系统都基本是以集群形式进行部署,而且微服务架构的系统居多,所有本章节主要介绍一下基于Redis和Lua
脚本实现分布式锁。
Redis分布式锁原理:
set [keyName] [vaule] NX PX 10_000
keyName: 顾名思义,这个是key;
vaule: 为了释放锁,该值要确保每个进程的唯一性,因此使用 UUID;
NX:如果key存在则SET失败,否则成功;
PX: 过期时间,失效时间,为了是过了时间自动释放锁。
Lua表达式:
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
end
RedisLockUtil类
/**
* description: redis工具类
*
* @author: YJG
* @time: 2021/1/16 15:45
*/
public class RedisLockUtil implements AutoCloseable{
private RedisTemplate redisTemplate;
private long expireTime;
private String redisKey;
private String redisValue;
public RedisLockUtil( RedisTemplate redisTemplate,long expireTime,String redisKey){
this.redisTemplate = redisTemplate;
this.expireTime = expireTime;
this.redisKey = redisKey;
this.redisValue = UUID.randomUUID().toString();
}
public Boolean getLock(){
RedisCallback<Boolean> redisCallback = connection -> {
//设置NX 如果key存在则返回set失败,不存在则成功
RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
//设置过期时间 s
Expiration seconds = Expiration.seconds(expireTime);
//序列化Key
byte[] keyByte = redisTemplate.getKeySerializer().serialize(redisKey);
//序列化value
byte[] valueByte = redisTemplate.getValueSerializer().serialize(redisValue);
//执行setnx
Boolean result = connection.set(keyByte, valueByte, seconds, setOption);
return result;
};
Boolean execute = (Boolean)redisTemplate.execute(redisCallback);
return execute;
}
public Boolean unLock(){
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";
RedisScript redisScript = RedisScript.of(script, Boolean.class);
List<String> keys = Arrays.asList(redisKey);
Boolean execute = (Boolean)redisTemplate.execute(redisScript, keys, redisValue);
return execute;
}
@Override
public void close() throws Exception {
//java7 特性
unLock();
}
}