redis实现分布锁

目录

前言

实现

注意

加解锁

jedis集群,哨兵模式在spring的配置


前言

参考: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">


	<!--	&lt;!&ndash;哨兵配置&ndash;&gt; 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>

	<!--	&lt;!&ndash;配置redislock组件&ndash;&gt;-->
	<!--	<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>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值