package com.dlss.loyalty.common.util;
import com.dlss.common.redis.RedisClientTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
@Component
@Slf4j
public class RedisLock {
private static final String PREFIX = "loyalty:lock:";
@Resource
private RedisClientUtil redisClientTemplate;
/*
lockName 锁名称
acquireTimeOut 等待时间
lockTimeout 过期时间
*/
public String lock(String lockName, long acquireTimeout, long lockTimeout) {
String identifier = UUID.randomUUID().toString();
String lockKey = PREFIX + lockName;
// 锁的过期时间
int lockExpire = (int) (lockTimeout / 1000); //锁过期时间
long end = System.currentTimeMillis() + acquireTimeout; //获取锁等待时间
while (System.currentTimeMillis() < end) {
//setnx 判断锁是否存在,不存在则添加锁并设置失效时间
if (redisClientTemplate.setnx(lockKey, identifier) == 1) {
redisClientTemplate.expire(lockKey, lockExpire);
return identifier;
}
//ttl -1 锁存在,但已经失效,重新添加锁失效时间;-2 锁不存在
if (redisClientTemplate.ttl(lockKey) == -1) {
redisClientTemplate.expire(lockKey, lockExpire);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error("获取分布式锁失败", e);
return null;
}
}
return null;
}
public boolean unlock(String lockName, String identifier){
String lockKey = PREFIX + lockName;
while (true) {
Jedis shard = redisClientTemplate.getShard("0");
shard.watch(lockKey);//监视key,事务执行之前这个key 被其他命令所改动,那么事务将被打断
if(identifier.equals(redisClientTemplate.get(lockKey))){
Transaction transaction = shard.multi();//标记事务
transaction.del(lockKey);
List<Object> exec = transaction.exec();//提交事务
if(exec == null){
continue;
}
return true;
}
shard.unwatch();
break;
}
return false;
}
}