/3 分钟/4 阅读/0 评论
redis分布式锁工具类
import cn.hutool.core.util.StrUtil;
import com.wdtrip.common.response.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class RedisLockService {
private static final DefaultRedisScript<Long> REDIS_LOCK_SCRIPT;
// 默认的过期时间:5分钟
private static final Integer DEFAULT_EXPIRE = 5 * 60;
// 获取锁的最大重试次数: 1次
private static final Integer DEFAULT_MAX_COUNT = 1;
// 默认睡眠时间。当获取次数大于 1 次时,如果第一次未获取到锁,则会睡眠, 默认睡眠200毫秒
private static final Long DEFAULT_SLEEP_MILLIS = 200L;
public static final String DEFAULT_ERROR_MSG = "can not get lock";
static {
DefaultRedisScript<Long> script = new DefaultRedisScript<>();
script.setResultType(Long.class);
script.setScriptSource(new ResourceScriptSource(new ClassPathResource("RedisLock.lua")));
REDIS_LOCK_SCRIPT = script;
}
@Autowired
private StringRedisTemplate redisTemplate;
public Result<?> exec(String key, Action action) {
return exec(key, action, DEFAULT_EXPIRE);
}
public Result<?> exec(String key, Action action, Integer expire) {
return exec(key, action, expire, DEFAULT_MAX_COUNT, DEFAULT_SLEEP_MILLIS);
}
/**
* @param key
* @param action 获取到锁后,需要执行的动作
* @param expire 锁存活时间/秒
* @param maxCount 获取锁的最大尝试次数
* @param sleep 当 maxCount > 1 时,如果第一次未获取到锁,则睡眠指定时间之后,再重新获取锁
* @return
*/
public Result<?> exec(String key, Action action, Integer expire, Integer maxCount, Long sleep) {
for (Integer count = 0; count < maxCount; count++) {
// 如果获取锁抛出异常,则继续向外抛出
boolean lock = getLock(key, expire);
if (lock) {
// 执行业务
try {
return action.doAction();
} catch (Exception e) {
log.error("RedisLock: 成功获取锁,执行动作异常", e);
return Result.error(-1, StrUtil.format("执行动作异常: {}", e.getMessage()));
} finally {
releaseLock(key);
}
}
if (maxCount > 1) {
try {
TimeUnit.MILLISECONDS.sleep(sleep);
} catch (InterruptedException e) {
return Result.error(-1, DEFAULT_ERROR_MSG);
}
}
}
return Result.error(-1, DEFAULT_ERROR_MSG);
}
/**
* 获取锁
*
* @param key
* @param expire
* @return
*/
private boolean getLock(String key, Integer expire) {
Long res = redisTemplate.execute(REDIS_LOCK_SCRIPT, Arrays.asList(key), expire.toString());
return res == 1;
}
private boolean releaseLock(String key) {
return redisTemplate.delete(key);
}
public interface Action {
Result<?> doAction();
}
}
import cn.hutool.core.util.StrUtil;
import com.wdtrip.common.response.Result;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class RedissonLockService {
// 默认的过期时间:5分钟
private static final Integer DEFAULT_EXPIRE = 5 * 60;
// 获取锁的最大重试次数: 1次
private static final Integer DEFAULT_MAX_COUNT = 1;
// 默认睡眠时间。当获取次数大于 1 次时,如果第一次未获取到锁,则会睡眠, 默认睡眠200毫秒
private static final Long DEFAULT_SLEEP_MILLIS = 200L;
public static final String DEFAULT_ERROR_MSG = "try to get the lock fail";
@Autowired
private RedissonClient redissonClient;
public Result<?> exec(String key, Boolean choose, Action action) {
return exec(key, action, DEFAULT_EXPIRE, DEFAULT_MAX_COUNT, DEFAULT_SLEEP_MILLIS, choose);
}
/**
* @param key
* @param action 获取到锁后,需要执行的动作
* @param expire 锁存活时间/秒
* @param maxCount 获取锁的最大尝试次数
* @param sleep 当 maxCount > 1 时,如果第一次未获取到锁,则睡眠指定时间之后,再重新获取锁
* @param choose true 手动释放锁
* @return
*/
public Result<?> exec(String key,
Action action,
Integer expire,
Integer maxCount,
Long sleep,
Boolean choose) {
for (int count = 0; count < maxCount; count++) {
try {
RLock rLock = redissonClient.getLock(key);
if (rLock.tryLock(0, expire, TimeUnit.SECONDS)) {
// 执行业务
try {
return action.doAction();
} catch (Exception e) {
log.error("RedisLock: 成功获取锁,执行动作异常", e);
return Result.error(-1, StrUtil.format("执行动作异常: {}", e.getMessage()));
} finally {
release(choose,rLock);
}
}
if (maxCount > 1) {
TimeUnit.MILLISECONDS.sleep(sleep);
}
} catch (InterruptedException e) {
log.error("尝试获取分布式锁失败,key={}", key);
return Result.error(-2, "尝试获取分布式锁失败");
}
}
return Result.error(-1, DEFAULT_ERROR_MSG);
}
public void release(Boolean choose,RLock rLock){
if (choose) {
rLock.unlock();
}
}
public interface Action {
Result<?> doAction();
}
}