大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE稳定放心使用
一、前置配置
需要已经集成成功JedisCluster
本人已实践的参考:https://blog.csdn.net/NullToSay/article/details/109813194
二、定义RedisLock类
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.exceptions.JedisNoScriptException;
import java.util.ArrayList;
import java.util.List;
public class RedisLock {
private static final Logger log = LoggerFactory.getLogger(RedisLock.class);
private JedisCluster jedisCluster;
/**
* lua脚本:判断锁住值是否为当前线程持有,是的话解锁,不是的话解锁失败
*/
private static final String DISTRIBUTE_LOCK_SCRIPT_UNLOCK_VAL = "if" +
" redis.call('get', KEYS[1]) == ARGV[1]" +
" then" +
" return redis.call('del', KEYS[1])" +
" else" +
" return 0" +
" end";
private volatile String unlockSha1 = "";
private static final Long UNLOCK_SUCCESS_CODE = 1L;
private static final String LOCK_SUCCESS_CODE = "ok";
public RedisLock(JedisCluster jedisCluster) {
this.jedisCluster = jedisCluster;
}
/**
* 根据loopTryTime循环重试
* @param lockKey 锁key
* @param lockVal 锁值,用于解锁校验
* @param expiryTime 锁过期时间
* @param loopTryTime 获取失败时,循环重试获取锁的时长
* @return 是否获得锁
*/
public boolean lock(String lockKey, String lockVal, long expiryTime, long loopTryTime){
Long endTime = System.currentTimeMillis() + loopTryTime;
while (System.currentTimeMillis() < endTime){
if (lock(lockKey, lockVal, expiryTime)){
return true;
}
}
return false;
}
/**
* 根据loopTryTime循环重试
* @param lockKey 锁key
* @param lockVal 锁值,用于解锁校验
* @param expiryTime 锁过期时间
* @param retryTimes 重试次数
* @param setpTime 每次重试间隔 mills
* @return 是否获得锁
*/
public boolean lock(String lockKey, String lockVal, long expiryTime, int retryTimes, long setpTime){
while (retryTimes > 0){
if (lock(lockKey, lockVal, expiryTime)){
return true;
}
retryTimes--;
try {
Thread.sleep(setpTime);
} catch (InterruptedException e) {
log.error("get distribute lock error" +e.getLocalizedMessage());
}
}
return false;
}
/**
* 一次尝试,快速失败。不支持重入
* @param lockKey 锁key
* @param lockVal 锁值,用于解锁校验
* @param expiryTime 锁过期时间 MILLS
* @return 是否获得锁
*/
public boolean lock(String lockKey, String lockVal, long expiryTime){
//相比一般的分布式锁,这里把setNx和setExpiry操作合并到一起,jedis保证原子性,避免连个命令之间出现宕机等问题
//这里也可以我们使用lua脚本实现
String result = jedisCluster.set(lockKey, lockVal, "NX", "PX", expiryTime);
return LOCK_SUCCESS_CODE.equalsIgnoreCase(result);
}
/**
* 释放分布式锁,释放失败最可能是业务执行时间长于lockKey过期时间,应当结合业务场景调整过期时间
* @param lockKey 锁key
* @param lockVal 锁值
* @return 是否释放成功
*/
public boolean unLock(String lockKey, String lockVal){
List<String> keys = new ArrayList<>();
keys.add(lockKey);
List<String> argv = new ArrayList<>();
argv.add(lockVal);
try {
Object result = jedisCluster.evalsha(unlockSha1, keys, argv);
return UNLOCK_SUCCESS_CODE.equals(result);
}catch (JedisNoScriptException e){
//没有脚本缓存时,重新发送缓存
log.info("try to store script......");
storeScript(lockKey);
Object result = jedisCluster.evalsha(unlockSha1, keys, argv);
return UNLOCK_SUCCESS_CODE.equals(result);
}catch (Exception e){
e.printStackTrace();
return false;
}
}
/**
* 由于使用redis集群,因此每个节点都需要各自缓存一份脚本数据
* @param slotKey 用来定位对应的slot的slotKey
*/
private void storeScript(String slotKey){
if (StringUtils.isEmpty(unlockSha1) || !jedisCluster.scriptExists(unlockSha1, slotKey)){
//redis支持脚本缓存,返回哈希码,后续可以继续用来调用脚本
unlockSha1 = jedisCluster.scriptLoad(DISTRIBUTE_LOCK_SCRIPT_UNLOCK_VAL, slotKey);
}
}
}
三、对象初始化
在配置文件内,初始化RedisLock对象(注入JedisCluster)
@Bean
//定义分布式锁对象
public RedisLock redisLock(JedisCluster jedisCluster){
return new RedisLock(jedisCluster);
}
最后JedisClusterConfig配置文件变为
import com.yntrust.tcmp.management.service.utils.RedisLock;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.util.HashSet;
import java.util.Set;
@Configuration
public class JedisClusterConfig {
//redis集群节点列表
@Value("${spring.redis.cluster.nodes}")
private String clusterNodes;
//redis集群连接超时时间
@Value("${spring.redis.cluster.timeout}")
private Long timeout;
//redis集群最大连接次数
@Value("${spring.redis.cluster.max-redirects}")
private int redirects;
//redis集群连接密码
@Value("${spring.redis.cluster.password}")
private String password;
@Bean
//重写JedisConnectionFactory方法,注入密码,否则会报认证错误(这个初始化,在getJedisCluster()之前,所以没有读到密码)
public JedisConnectionFactory connectionFactory(){
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
connectionFactory.setPassword(password);
return connectionFactory;
}
@Bean
//定义分布式锁对象
public RedisLock redisLock(JedisCluster jedisCluster){
return new RedisLock(jedisCluster);
}
@Bean
//定义JedisCluster对象
public JedisCluster getJedisCluster(){
String [] serverArray=clusterNodes.split(",");
Set<HostAndPort> nodes=new HashSet<>();
for (String ipPort:serverArray){
String [] ipPortPair=ipPort.split(":");
nodes.add(new HostAndPort(ipPortPair[0].trim(),Integer.valueOf(ipPortPair[1].trim())));
}
JedisCluster jedisCluster = new JedisCluster(nodes,timeout.intValue(),timeout.intValue(),redirects,password,new GenericObjectPoolConfig());
return jedisCluster;
}
}
四、使用
在需要使用锁的业务模块,用
@Autowired private RedisLock redisLock;
注入使用
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181966.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...