前言:随着行業的發展和微服務分布式的興起,由此會引來并發問題,如果單服務單機情況可以不去考慮分布式鎖。
但是,現在系統都基本是以叢集形式進行部署,而且微服務架構的系統居多,所有本章節主要介紹一下基于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();
}
}