话不多说直接上源码:
import java.util.Collections;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
/**
* 使用redis构建分布式锁(使用lun语言)
* @author fangyuan
*
*/
public class RedisLock {
private static final Long RELEASE_SUCCESS = 1L;
/**
* 尝试获取分布式锁
* @param redisTemplate Redis客户端
* @param lockKey 锁 redis key
* @param requestId 请求标识 redis value
* @param expireTime lock超期时间
* @return 是否获取成功
*/
public static boolean tryGetDistributedLock(RedisTemplate redisTemplate , String lockKey, String requestId, int expireTime) {
String scriptText = "if redis.call('setNx',KEYS[1],ARGV[1]) == 1 then if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end else return 0 end";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setResultType(Long.class);
redisScript.setScriptText(scriptText);
Long result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey),requestId,String.valueOf(expireTime));
if(RELEASE_SUCCESS.equals(result)){
return true;
}
return false;
}
/**
* 释放分布式锁
* @param redisTemplate Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @return 是否释放成功
*/
public static boolean releaseDistributedLock(RedisTemplate redisTemplate, String lockKey, String requestId) {
String scriptText = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setResultType(Long.class);
redisScript.setScriptText(scriptText);
Long result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), requestId);
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
其中需要设置RedisTemplate 对于Key,Value的序列化器为StringRedisSerializer
RedisTemplate<String, Object> template = new RedisTemplate<>();
StringRedisSerializer srs = new StringRedisSerializer();
template.setKeySerializer(srs);
template.setValueSerializer(srs);
使用:
String lockKey = CacheConstant.LOCK_KEY;
//随机生成id
String requestId = UUID.randomUUID().toString();
//加入分布式锁保证只有一个请求操作
if(RedisLock.tryGetDistributedLock(dtcRedisTemplate,lockKey,requestId,expireTime)){
try{
//业务代码
}catch (Exception e){
e.printStackTrace();
}finally {
RedisLock.releaseDistributedLock(dtcRedisTemplate,lockKey,requestId);
}
}else{
throw new RuntimeException("该分布式锁已被使用。。。。");
}
后续会使用zookeeper构建分布式锁,并总结两者不同,以及两种方式的不同使用场景