springboot新版本使用lettuce取代了jedis連接redis,分佈式鎖實現代碼如下
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* @author Vick C
* @Description: 分佈式鎖工具類
* @CreateDate: 2020/05/29
*/
@Component
@Slf4j
public class RedisLock {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 釋放鎖腳本,原子操作,lua腳本
*/
private static final String UNLOCK_LUA;
/**
* 默認過期時間(30ms)
*/
private static final long DEFAULT_EXPIRE = 30L;
static {
StringBuilder sb = new StringBuilder();
sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
sb.append("then ");
sb.append(" return redis.call(\"del\",KEYS[1]) ");
sb.append("else ");
sb.append(" return 0 ");
sb.append("end ");
UNLOCK_LUA = sb.toString();
}
/**
* 獲取分佈式鎖,原子操作
* @param lockKey 鎖
* @param lockValue 唯一ID, 可以使用UUID.randomUUID().toString();
* @return 是否枷鎖成功
*/
public boolean lock(String lockKey, String lockValue) {
return this.lock(lockKey, lockValue, DEFAULT_EXPIRE, TimeUnit.MILLISECONDS);
}
/**
* 獲取分佈式鎖,原子操作
* @param lockKey 鎖
* @param lockValue 唯一ID, 可以使用UUID.randomUUID().toString();
* @param expire 過期時間
* @param timeUnit 時間單位
* @return 是否枷鎖成功
*/
public boolean lock(String lockKey, String lockValue, long expire, TimeUnit timeUnit) {
try {
RedisCallback<Boolean> callback = (connection) -> connection.set(lockKey.getBytes(StandardCharsets.UTF_8),
lockKey.getBytes(StandardCharsets.UTF_8), Expiration.seconds(timeUnit.toSeconds(expire)),
RedisStringCommands.SetOption.SET_IF_ABSENT);
return redisTemplate.execute(callback);
} catch (Exception e) {
log.error("redis lock error ,lock key: {}, value : {}, error info : {}", lockKey, lockValue, e);
}
return false;
}
/**
* 釋放鎖
* @param lockKey 鎖
* @param lockValue 唯一ID
* @return 執行結果
*/
public boolean unlock(String lockKey, String lockValue) {
RedisCallback<Boolean> callback = (connection) -> connection.eval(UNLOCK_LUA.getBytes(), ReturnType.BOOLEAN, 1, lockKey.getBytes(StandardCharsets.UTF_8), lockValue.getBytes(StandardCharsets.UTF_8));
return redisTemplate.execute(callback);
}
/**
* 獲取Redis鎖的value值
* @param lockKey 鎖
*/
public String get(String lockKey) {
try {
RedisCallback<String> callback = (connection) -> new String(Objects.requireNonNull(connection.get(lockKey.getBytes())), StandardCharsets.UTF_8);
return redisTemplate.execute(callback);
} catch (Exception e) {
log.error("get redis value occurred an exception,the key is {}, error is {}", lockKey, e);
}
return null;
}
}