分布式锁之RedissonLock

news2024/11/24 14:28:21

什么是Redisson?
俗话说他就是看门狗,看门狗机制是一种用于保持Redis连接活跃性的方法,通常用于分布式锁的场景。看门狗的工作原理是:当客户端获取到锁之后,会对Redis中的一个特定的键设置一个有限的过期时间,然后每隔一段时间(默认是15秒),客户端会对这个键“续约”,即重新设置它的过期时间,以此来保持锁的持有状态,防止锁因为某些原因(如客户端崩溃或网络问题)而被释放。
在这里插入图片描述
以下是核心实战部分
配置文件读取

@ConfigurationProperties(
        prefix = "spring.redis.redisson"
)
@Data
public class RedissonProperties {

    /**
     * key前缀
     */
    private String keyPrefix;

    /**
     * 拿锁等待时间(毫秒)
     */
    private long waitTime = 10000;

    /**
     * 默认ttl时间(毫秒)
     */
    private long leaseTime = 60000;

    @Value("${spring.redis.redisson.config.clusterServersConfig.nodeAddresses}")
    private String nodeAddresses;

    @Value("${spring.redis.redisson.config.clusterServersConfig.scanInterval}")
    private Integer scanInterval;

    @Value("${spring.redis.redisson.config.threads}")
    private Integer threads;

    @Value("${spring.redis.redisson.config.nettyThreads}")
    private Integer nettyThreads;

    @Value("${spring.redis.redisson.config.transportMode}")
    private String transportMode;
}

yml文件

spring:
  ##redis集群配置
  redis:
    database: 0
    timeout: 5000ms
    redisson:
      config:
        clusterServersConfig:
          nodeAddresses: redis://10.xxx.xx.x1:6379,redis://10.xxx.xx.x2:6379,redis://10.xxx.xx.x3:6379
          scanInterval: 1000
        nettyThreads: 0
        threads: 0
        transportMode: NIO
      key-prefix: test:key
      lease-time: 80000
      wait-time: 50000

redisson自动配置类

@Configuration
@ConditionalOnClass({Redisson.class})
@EnableConfigurationProperties({RedissonProperties.class})
@Slf4j
public class RedissonAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean({RedisConnectionFactory.class})
    public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
        return new RedissonConnectionFactory(redisson);
    }

    @Bean(
            destroyMethod = "shutdown"
    )
    @ConditionalOnMissingBean({RedissonClient.class})
    public RedissonClient redisson(RedissonProperties redissonProperties) throws IOException {
        Config config = new Config();
        config.useClusterServers().addNodeAddress(redissonProperties.getNodeAddresses().split(","))
                .setScanInterval(redissonProperties.getScanInterval());
        config.setThreads(redissonProperties.getThreads())
                .setNettyThreads(redissonProperties.getNettyThreads())
                .setTransportMode(TransportMode.valueOf(redissonProperties.getTransportMode()));
        return Redisson.create(config);
    }

    @Bean
    @ConditionalOnMissingBean(
            name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

}

redis的缓存类实现

@Service
public class RedisCache {

	@Autowired
    private RedissonClient redisson;

	@Autowired
    private RedissonProperties redissonProperties;

	/**
     * 缓存
     *
     * @param key 缓存key
     * @param <T>
     * @return 缓存返回值
     */
    public <T> T get(String key) {
        RBucket<T> bucket = redisson.getBucket(getKey(key));
        return bucket.get();
    }

    /**
     * 以string的方式读取缓存
     *
     * @param key 缓存key
     * @return 缓存返回值
     */
    public String getString(String key) {
        RBucket<String> bucket = redisson.getBucket(getKey(key), StringCodec.INSTANCE);
        return bucket.get();
    }

    /**
     * 以string的方式保存缓存(与其他应用共用redis时需要使用该函数)
     *
     * @param key     缓存key
     * @param value   缓存值
     * @param expiredTime 缓存过期时间
     */
    public void putString(String key, String value, long expiredTime) {
        RBucket<String> bucket = redisson.getBucket(getKey(key), StringCodec.INSTANCE);
        bucket.set(value, expiredTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 如果不存在则写入缓存(string方式,不带有redisson的格式信息)
     *
     * @param key     缓存key
     * @param value   缓存值
     * @param expiredTime 缓存过期时间
     */
    public boolean putStringIfAbsent(String key, String value, long expiredTime) {
        RBucket<String> bucket = redisson.getBucket(getKey(key), StringCodec.INSTANCE);
        return bucket.trySet(value, expiredTime, TimeUnit.MILLISECONDS);
    }


    /**
     * 设置缓存
     *
     * @param key     缓存key
     * @param value   缓存值
     * @param expiredTime 缓存过期时间
     * @param <T>     类型
     */
    public <T> void put(String key, T value, long expiredTime) {
        RBucket<T> bucket = redisson.getBucket(getKey(key));
        bucket.set(value, expiredTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 如果不存在则设置缓存
     *
     * @param key     缓存key
     * @param value   缓存值
     * @param expiredTime 缓存过期时间
     * @param <T>     类型
     */
    public <T> void putIfAbsent(String key, T value, long expiredTime) {
        RBucket<T> bucket = redisson.getBucket(getKey(key));
        bucket.trySet(value, expiredTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 移除缓存
     *
     * @param key
     */
    public void remove(String key) {
        redisson.getBucket(getKey(key)).delete();
    }

    /**
     * 判断缓存是否存在
     *
     * @param key
     * @return
     */
    public boolean exists(String key) {
        return redisson.getBucket(getKey(key)).isExists();
    }

    private String getKey(String key) {
    	return StringUtils.format("{0}:{1}", redissonProperties.getKeyPrefix(), key);
    }

获取和释放分布式锁接口
DistributedLock

/**
	 * get分布式锁
	 * @param lockKey
	 * @param requestId
	 * @param expireTime
	 * @return
	 */
	public boolean getDistributedLock(String lockKey, String requestId, long expireTime);
	
	/**
	 * remove分布式锁
	 * @param lockKey
	 * @param requestId
	 * @return
	 */
	public boolean removeDistributedLock(String lockKey, String requestId);

实现DistributedLock的实现类逻辑

@Service
public class RedisDistributedLocker implements DistributedLocker {
    private static final Logger logger = LoggerFactory.getLogger(RedisDistributedLocker.class);

    @Autowired
    private RedissonClient redisson;

    @Autowired
    private RedissonProperties redissonProperties;

 
    public boolean getDistributedLock(String lockKey, String flagId, long expireTime) {
        boolean success;
        try {
            if (expireTime == 0) {
                expireTime = redissonProperties.getLeaseTime();
            }
            lockKey = StringUtils.format("{0}:{1}", redissonProperties.getKeyPrefix(), lockKey);
            RLock locker = redisson.getLock(lockKey);
            success = locker.tryLock(redissonProperties.getWaitTime(), expireTime, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            success = false;
            logger.error(StringUtils.format("获取分布式锁失败,lockKey={0}, flagId={1}, expirTime={2}", lockKey, flagId, expireTime), e);
        }
        return success;
    }

    public boolean releaseDistributedLock(String lockKey, String flagId) {
        boolean success = false;
        try {
            lockKey = StringUtils.format("{0}:{1}", redissonProperties.getKeyPrefix(), lockKey);
            RLock locker = redisson.getLock(lockKey);
            if (locker.isHeldByCurrentThread()) {
                locker.unlock();
                success = true;
            }
        } catch (Exception e) {
            success = false;
            logger.error(StringUtils.format("分布式锁失败,lockKey={0}, flagId={1}", lockKey, flagId), e);
        }
        return success;
    }

在需要的业务场景下使用 以下为伪代码

try {
            boolean ock = distributedLocker.getDistributedLock(lockKey, flagId, 9000L);
            if (!ock) {
                return;
            }
            // 实现自己的业务逻辑。。。。。。。。。。。。。。。。。。。。。。。。。
			
        } catch (Exception e) {
            e.printStackTrace();
            
            throw new RuntimeException(e.getMessage());
        } finally {
            distributedLocker.releaseDistributedLock(lockKey, flagId);
        }

以上的是分布式锁之RedissonLock 若需完整代码 可识别二维码后 给您发代码。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1672141.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

易我分区大师18.5发布上线:全方位提升您的磁盘管理体验

近期&#xff0c;易我分区大师18.5版本正式发布上线&#xff01; 新版本在原有基础上进行了升级和优化&#xff0c;不仅继承了前版本的强大功能&#xff0c;还新增了C盘数据迁移、清除Windows PIN码以及蓝屏问题助手等实用功能&#xff0c;帮助用户更轻松、更高效地管理电脑磁…

车载电子电器架构 —— UDS Service 11介绍

车载电子电器架构 —— UDS Service 11介绍 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证…

栈的相关操作练习:用栈实现队列

1.思路解析 首先了解&#xff0c;队列遵循先进先出&#xff0c;栈遵循后进先出&#xff0c;所以利用两个栈popst与pushst进行元素转移后可以实现先进先出的功能。原题来源于leetcode中的:232.用队列实现栈 2.操作详解 首先要自己写一个栈及其操作&#xff0c;这里直接给出&…

C++类与对象基础探秘系列(一)

目录 面向过程和面向对象初步认识 类的引入 类的定义 类的访问限定符及封装 访问限定符 封装 类的作用域 类的实例化 类的对象模型 如何计算类对象的大小 类对象的存储方式 结构体内存对齐规则 类成员函数的this指针 this指针的引出 this指针的特性 C语言和C实…

leetCode-hot100-位运算专题

例题中的视频讲解是B站中的宝藏博主的讲解视频&#xff0c;每道题后面都附有该题对应的视频链接~ 位运算知识总结 1.异或2.与运算和或运算3.左移和右移4.综合例题 1.异或 参考资料&#xff1a;位运算-异或&#xff0c;以下知识点讲解的内容参考了该篇博文&#xff0c;有兴趣的…

MySQL表结构的一些设计经验分享

我们在对一张表进行设计时&#xff0c;还要遵守一些基本的原则&#xff0c;比如经常听见的“范式准则”。但范式准则过于理论&#xff0c;在真实业务中&#xff0c;不必严格遵守三范式的要求。而且有时为了性能考虑&#xff0c;还可以进行反范式的设计&#xff0c;比如在数据仓…

ATFX:美国通胀率平台期,或助力黄金延续涨势

ATFX金属&#xff1a;5月9日19:00至5月10日19:00&#xff0c;COMEX黄金的小时级别出现一波持续24小时的上涨走势&#xff0c;最高触及2385.3美元&#xff0c;累计涨幅2.78%&#xff0c;成为上周最佳的短线交易时机。R阻力线形成后&#xff0c;COMEX黄金进入下降通道&#xff0c…

采油厂职工向媒体投稿的好方法找到了

作为一名采油厂的职工,我深知在媒体上定期投稿的重要性。这不仅是我们展示工作成果、传播企业文化的重要途径,更是上级考核我们工作表现的一项指标。然而,在投稿的过程中,我经历了不少心酸与困扰。 起初,我采用传统的邮箱投稿方式。每天,我都会花费大量时间在网络上搜索合适的媒…

ms17-010(永恒之蓝)

1.漏洞介绍: 永恒之蓝&#xff08;ms17-010&#xff09;爆发于2017年4月14日晚&#xff0c;是一种利用Windows系统的SMB协议漏洞来获取系统的最高权限&#xff0c;以此来控制被入侵的计算机。甚至于2017年5月12日&#xff0c; 不法分子通过改造“永恒之蓝”制作了wannacry勒索病…

n的阶乘(函数)(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//声明n的阶乘函数fac; int fac(int n);int main() {//初始化变量值&#xff1b;int n, result;//获取要阶乘的数&#xff1b;printf("请输入要阶乘的n&…

创新点!CNN与LSTM结合,实现更准预测、更快效率、更高性能!

推荐一个能发表高质量论文的好方向&#xff1a;LSTM结合CNN。 LSTM擅长捕捉序列数据中的长期依赖关系&#xff0c;而CNN则擅长提取图像数据的局部特征。通过结合两者的优势&#xff0c;我们可以让模型同时考虑到数据的时序信息和空间信息&#xff0c;减少参数降低过拟合风险&a…

怎么通过微信小程序实现远程控制8路控制器/断路器

怎么通过微信小程序实现远程控制8路控制器/断路器呢&#xff1f; 本文描述了使用微信小程序调用HTTP接口&#xff0c;实现控制8路控制器/断路器&#xff0c;支持8路输出&#xff0c;均可独立控制&#xff0c;可接入各种电器。 可选用产品&#xff1a;可根据实际场景需求&#…

【2024】Gradle安装配置以及基于Kotlin 进行详细使用

目录&#x1f4bb; 一、介绍二、安装Gradle1、下载安装2、配置环境变量2.1、mac2.2、windows 3、配置国内国内镜像源4、初始化Gradle项目4.1、项目结构4.2、Gradle常用命令 三、项目配置1、配置文件介绍1.1、设置文件settings.gradle1.1.1、单体项目1.1.2、父子项目 1.2、构建文…

车载电子电器架构 —— Vector对于车载以太网的解决方案(协议栈)

车载电子电器架构 —— Vector对于车载以太网的解决方案(协议栈) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你…

电子学会C/C++编程等级考试2024年03月(一级)真题解析

C/C++编程(1~8级)全部真题・点这里 第1题:倒序输出 依次输入4个整数a、b、c、d,将他们倒序输出,即依次输出d、c、b、a这4个数。 时间限制:1000 内存限制:65536 输入 一行4个整数a、b、c、d,以空格分隔。 0 < a,b,c,d < 108 输出 一行4个整数d、c、b、a,整数之间以…

探索人员定位系统的架构设计

随着科技的不断发展&#xff0c;人员定位系统在各个领域中扮演着越来越重要的角色。从室内定位到室外定位&#xff0c;从个人安全到物流管理&#xff0c;人员定位系统为我们提供了精准的位置信息&#xff0c;极大地促进了工作效率和安全管理。 但是&#xff0c;一个成功的人员…

docker 安装 Redis (附图文教程)

首先确保已安装docker 安装docker 拉取 redis 镜像 搜索镜像 docker search redis使用最多人使用的 拉取镜像 没有指定版本默认最新版本 docker pull redis查看镜像 docker images启动容器 创建挂载目录 mkdir -p /home/local/redis/conf /home/local/redis/data创建…

[算法][BFS][leetcode]994. 腐烂的橘子

题目地址 https://leetcode.cn/problems/rotting-oranges/description/ 错误解法 class Solution {public int orangesRotting(int[][] grid) {//层序遍历int ans 0;for (int i 0;i<grid.length;i) {for(int j 0;j<grid[0].length;j){boolean flag false;if(grid[i][j…

python EEL应用程序的启动过程

EEL 启动流程 初始化 EEL (eel.init()): 设定静态文件目录&#xff0c;通常是包含 HTML、CSS、JavaScript 等文件的目录。扫描指定目录下的 JavaScript 文件&#xff0c;寻找通过 eel.expose() 暴露的函数。 启动 Web 服务器 (eel.start()): 基于 Bottle 框架启动一个轻量级的 …

flexible.js+rem页面适配

简介 flexible.js 介绍 flexible.js 是一个用于移动端页面适配的 JavaScript 库&#xff0c;由阿里巴巴团队开发并开源。在移动 web 开发中&#xff0c;由于设备屏幕尺寸、分辨率以及像素比的差异&#xff0c;开发者通常需要编写额外的代码来确保页面在不同设备上都能正确显示…