目录
前言
参考:https://redis.io/commands/set
针对实现分布式锁,redis为方便用户实现,出现了set key value EX NX的系统命令进行实现。
注意:由于SET命令选项可以替换SETNX、SETEX、PSETEX、GETSET,因此在未来的 Redis 版本中,这些命令可能会被弃用并最终被删除。
所以以后可能SETNX这样的命令估计不存在了。
NX
-- 仅在不存在的情况下设置值。XX
-- 仅已存在的情况设置值
SET成功返回OK字符串,否则返回null。
实现
注意
JedisCluster集群模式下,jedis不需要释放连接,jedis会自己释放。
private T runWithRetries(byte[] key, int attempts, boolean tryRandomNode, boolean asking) {
if (attempts <= 0) {
throw new JedisClusterMaxRedirectionsException("Too many Cluster redirections?");
} else {
Jedis connection = null;
Object var7;
try {
if (asking) {
connection = (Jedis)this.askConnection.get();
connection.asking();
asking = false;
} else if (tryRandomNode) {
connection = this.connectionHandler.getConnection();
} else {
connection = this.connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key));
}
Object var6 = this.execute(connection);
return var6;
} catch (JedisNoReachableClusterNodeException var13) {
throw var13;
} catch (JedisConnectionException var14) {
this.releaseConnection(connection);
connection = null;
if (attempts <= 1) {
this.connectionHandler.renewSlotCache();
throw var14;
}
var7 = this.runWithRetries(key, attempts - 1, tryRandomNode, asking);
return var7;
} catch (JedisRedirectionException var15) {
if (var15 instanceof JedisMovedDataException) {
this.connectionHandler.renewSlotCache(connection);
}
this.releaseConnection(connection);
connection = null;
if (var15 instanceof JedisAskDataException) {
asking = true;
this.askConnection.set(this.connectionHandler.getConnectionFromNode(var15.getTargetNode()));
} else if (!(var15 instanceof JedisMovedDataException)) {
throw new JedisClusterException(var15);
}
var7 = this.runWithRetries(key, attempts - 1, false, asking);
} finally {
this.releaseConnection(connection);
}
return var7;
}
releaseConnection释放连接
加解锁
JedisCluster下加锁
public long lock(String key, String value,long time) {
String result=jedisPattern.set(key,value,"nx","px",time);
return (null==result||"".equals(result))?0L:1L;
}
哨兵和单实例模式加锁
public long lock(String key, String value,long time) {
Jedis jedis=jedisPattern.getResource();
String result=null;
try{
result=jedis.set(key,value,"nx","px",time);
return (null==result||"".equals(result))?0L:1L;
}finally {
if(null!=jedis)
{
jedis.close();
}
}
}
JedisCluster下解锁
luna解锁脚本
public final static String unLockScript = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
@Override
public long unLock(List<String> keys, List<String> args) {
return (Long) jedisPattern.eval(Constant.unLockScript, keys, args);
}
哨兵和单实例模式解锁
@Override
public long unLock(List<String> keys, List<String> args) {
Jedis jedis = jedisPattern.getResource();
try {
return (Long) jedis.eval(Constant.unLockScript, keys, args);
} finally {
if (null != jedis) {
jedis.close();
}
}
}
jedis集群,哨兵模式在spring的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- <!–哨兵配置–> 26379:时哨兵的端口-->
<!-- <bean id="jedisSentinelPool" class="redis.clients.jedis.JedisSentinelPool">-->
<!-- <constructor-arg index="0" value="mymaster"/>-->
<!-- <constructor-arg index="1">-->
<!-- <set>-->
<!-- <value>${redislock.addr1}:26379</value>-->
<!-- <value>${redislock.addr2}:26379</value>-->
<!-- <value>${redislock.addr3}:26379</value>-->
<!-- </set>-->
<!-- </constructor-arg>-->
<!-- <constructor-arg index="2" ref="commonRedisPoolConfig"/>-->
<!-- </bean>-->
<!-- redis连接池配置 -->
<bean id="commonRedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxWaitMillis" value="1000"/>
<property name="maxTotal" value="500"/>
<property name="minIdle" value="64"/>
<property name="maxIdle" value="500"/>
<property name="testOnBorrow" value="false"/>
</bean>
<!-- <!–配置redislock组件–>-->
<!-- <bean id="xxxx" class="xxxx">-->
<!-- <property name="jedisPattern" ref="jedisSentinelPool"/>-->
<!-- </bean>-->
<!--配置redislock组件-->
<bean id="xxx" class="xxxxxx">
<property name="jedisPattern" ref="jedisSentinelPool"/>
</bean>
<!--集群模式配置-->
<bean id="jedisSentinelPool" class="redis.clients.jedis.JedisCluster">
<constructor-arg index="0">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="ip"></constructor-arg>
<constructor-arg name="port" value="端口"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="ip"></constructor-arg>
<constructor-arg name="port" value="端口"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="ip"></constructor-arg>
<constructor-arg name="port" value="端口"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="ip"></constructor-arg>
<constructor-arg name="port" value="端口"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="ip"></constructor-arg>
<constructor-arg name="port" value="端口"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="ip"></constructor-arg>
<constructor-arg name="port" value="端口"></constructor-arg>
</bean>
</set>
</constructor-arg>
<constructor-arg index="1" ref="commonRedisPoolConfig"/>
</bean>
</beans>