jediscluster.set加锁_redislock

jediscluster.set加锁_redislock一、前置配置需要已经集成成功JedisCluster本人已实践的参考:https://blog.csdn.net/NullToSay/article/details/109813194二、定义RedisLock类importorg.apache.commons.lang.StringUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importredis.clients.jedis.JedisClust.

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新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;

注入使用

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/181966.html原文链接:https://javaforall.net

(0)
上一篇 2022年10月14日 下午7:46
下一篇 2022年10月14日 下午7:46


相关推荐

  • Ganglia集群监控

    Ganglia集群监控介绍 Ganglia 是 UCBerkeley 发起的一个开源集群监视项目 设计用于监控数以千计的节点 Ganglia 主要是用来监控系统性能 如 cpu mem 硬盘利用率 I O 负载 网络流量情况等 通过曲线很容易见到每个节点的工作状态 对合理调整 分配系统资源 提高系统整体性能起到重要作用 Ganglia 的核心包含 gmond gmetad 以及一个 Web 前端 gmond GangliaMonit

    2026年3月17日
    2
  • JAVA后端应该学什么技术?[通俗易懂]

    JAVA后端应该学什么技术?[通俗易懂]Java语言是最常见的后端开发语言之一,Java语言由于自身具备构建多线程的能力,且体系结构比较中立,所以在大型互联网平台的开发中得到了广泛的采用。目前要想从事Java的后端开发应该学习以下内容:第一,Servlet技术。Servlet技术是Java后端的重要技术之一,作为JavaWeb开发的核心组件,Servlet承担了WebMVC结构中的核心作用(功能导航)。传统的Model2结构…

    2022年7月8日
    27
  • python和c++哪个好_run pycharm community edition

    python和c++哪个好_run pycharm community edition在pycharm中使用django命令的过程中经常会用到pythonmanage.py相关的命令,每次都输入pythonmanage.py会比较麻烦,可以利用pycharm提供的tools来省去pythonmanage.py的重复输入。具体实现过程如下:先进入settings完成如下操作随后可勾选Tools中的Runmanage.pyTask完成后即可以直接输入manag…

    2022年8月26日
    10
  • python安装pygame教程_pygame 安装教程

    python安装pygame教程_pygame 安装教程步骤 1 去官网下载 PyGame 注意 要下载对应版本的包其中 如果 python 为以下版本 cp36 就是 python3 6 的意思 2 exe 文件直接安装 whl 文件启动 doc 命令安装 在文件所在位置打开 doc 界面 win10 直接在当前文件夹空白处按住 shift 右键打开 powershell 窗口 输入以下指令安装 pipinstallpy 1 9 3 cp36 cp36m

    2026年3月19日
    2
  • Linux命令 – ls命令

    Linux命令 – ls命令Linux 命令 ls 命令 ls 命令是 linux 下最常用的命令 ls 命令就是 list 的缩写 用来打印出当前目录的清单 如果 ls 指定其他目录 那么就会显示指定目录里的文件及文件夹清单 通过 ls 命令不仅可以查看 linux 文件夹包含的文件 而且可以查看文件权限 包括目录 文件夹 文件权限 查看目录信息等等 1 语法 ls 选项 目录或者文件 2 功能 列出目录的内容 包括文件和子目录的名称 3 参数 1 每列仅显示一个文件或目录名称 a 或 all 下所有文件和目录 A

    2025年11月16日
    5
  • AI Agent完整开发流程:从概念设计到生产部署的企业级实战手册

    AI Agent完整开发流程:从概念设计到生产部署的企业级实战手册

    2026年3月16日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号