Spring Boot3 Redisson 项目地址

https://gitee.com/supervol/loong-springboot-study

(记得给个start,感谢)

Redisson 介绍

        在分布式系统中,多节点部署的应用对共享资源(如数据库记录、缓存键、文件)的并发访问需要分布式锁来保证互斥性,避免数据不一致问题。Spring Boot 3 生态中,Redisson 是实现分布式锁的主流方案之一 —— 它基于 Redis 封装了完整的分布式锁功能,解决了原生 Redis 实现锁的诸多痛点(如手动续期、不可重入、释放他人锁等),提供了高可用、易扩展的分布式锁能力。

Redisson 核心

1. 为什么需要分布式锁

        单机应用中,synchronized 或 java.util.concurrent.locks.Lock 可解决并发问题,但分布式系统中多节点共享资源时,单机锁失效(各节点内存独立),需跨节点的 “全局锁”:

  • 核心需求:互斥性(同一时间仅一个节点持有锁)、安全性(避免死锁)、可用性(锁服务不宕机)、重入性(同一线程可重复获取锁)、公平性(可选,按请求顺序获取)。
  • 原生 Redis 痛点:需手动实现 setNx+expire 原子操作、手动处理锁续期、无法原生支持重入、可能释放他人锁,而 Redisson 封装了这些细节。

2. Redisson 是什么

        Redisson 是基于 Redis 的 Java 分布式客户端,不仅提供 Redis 基础操作(如字符串、哈希、列表),还内置了大量分布式场景工具类,核心能力包括:

  • 分布式锁(可重入锁、公平锁、读写锁等);
  • 分布式集合(分布式 Map、Set、Queue);
  • 分布式信号量、计数器、限流器;
  • 支持 Redis 单机、集群、哨兵、主从等所有部署模式。

        其中,分布式锁是 Redisson 最核心的功能,它通过 Redis 的 Hash 数据结构和 Lua 脚本保证锁的原子性,同时提供 “看门狗(Watch Dog)” 机制解决锁续期问题。

Redisson 使用

        Redisson 提供多种分布式锁类型,可重入锁(RLock) 是最常用的基础锁,其他锁(公平锁、读写锁等)均基于其扩展。

1. 可重入锁(RLock)

        可重入锁支持同一线程多次获取锁(解决 “自己锁自己” 的问题),且内置 Watch Dog 自动续期 机制,避免业务未执行完锁已过期。

(1)核心 API

方法功能说明
lock()阻塞获取锁,默认启用 Watch Dog(leaseTime=-1),直到获取成功
lock(long leaseTime, TimeUnit unit)带过期时间的锁,leaseTime 后自动释放,禁用 Watch Dog
tryLock()非阻塞获取锁,立即返回 true(成功)或 false(失败)
tryLock(long waitTime, long leaseTime, TimeUnit unit)带等待时间的非阻塞锁:
waitTime:获取锁的最大等待时间(超时返回 false
leaseTime:锁的过期时间(0 或 -1 启用 Watch Dog)
unlock()释放锁,必须在 finally 中调用,避免死锁
isHeldByCurrentThread()判断当前线程是否持有锁,避免释放他人锁

(2)代码示例

        生产环境中优先使用 tryLock 避免无限阻塞,同时在 finally 中安全释放锁:

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class OrderService {@Autowiredprivate RedissonClient redissonClient;// 分布式锁的 Key(需保证业务唯一性,如“订单创建_用户ID”)private static final String LOCK_KEY = "order:create:%s";/*** 创建订单(分布式锁保护)* @param userId 用户ID(用于生成唯一锁Key)*/public void createOrder(Long userId) {RLock lock = null;try {// 1. 生成唯一锁Key(按用户ID区分,避免锁冲突)String lockKey = String.format(LOCK_KEY, userId);// 2. 获取可重入锁lock = redissonClient.getLock(lockKey);// 3. 尝试获取锁:等待3秒,持有5秒(若5秒内未释放,锁自动过期)boolean isLocked = lock.tryLock(3, 5, TimeUnit.SECONDS);if (!isLocked) {// 4. 获取锁失败,返回友好提示throw new RuntimeException("当前操作过频繁,请稍后再试");}// 5. 获取锁成功,执行核心业务(如创建订单、扣减库存)System.out.println("获取锁成功,执行订单创建逻辑...");// 模拟业务耗时(如2秒)TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException("订单创建失败");} finally {// 6. 安全释放锁:仅释放当前线程持有的锁if (lock != null && lock.isHeldByCurrentThread()) {lock.unlock();System.out.println("锁释放成功");}}}
}

2. Watch Dog 自动续期

        当 leaseTime 未设置(或设为 -1)时,Redisson 会启动 Watch Dog 机制,解决 “业务未执行完锁已过期” 的问题:

  • 原理:Watch Dog 是一个后台线程,在锁快过期时(默认剩余 10 秒)自动将锁的过期时间延长至 30 秒;
  • 默认配置:锁默认过期时间 30 秒,续期间隔 10 秒;
  • 禁用场景:若手动设置 leaseTime(如 5 秒),Watch Dog 会失效,锁会在 leaseTime 后强制释放,需确保 leaseTime 大于业务执行时间。

3. 其他常用锁类型

        Redisson 提供多种锁类型,满足不同分布式场景需求:

(1)公平锁(RedissonFairLock)

        按请求顺序获取锁,避免 “饥饿问题”(某些线程长期获取不到锁),适用于对公平性要求高的场景(如秒杀排队)。使用示例

// 获取公平锁(替换 getLock 为 getFairLock)
RLock fairLock = redissonClient.getFairLock("order:create:1001");
try {if (fairLock.tryLock(3, 5, TimeUnit.SECONDS)) {// 执行公平锁保护的业务逻辑}
} finally {if (fairLock != null && fairLock.isHeldByCurrentThread()) {fairLock.unlock();}
}

(2)读写锁(RReadWriteLock)

        读锁共享,写锁互斥,适用于 “读多写少” 的场景(如商品详情查询、库存更新),提高并发效率:

  • 读锁(共享):多个线程可同时获取读锁,互不阻塞;
  • 写锁(互斥):仅一个线程可获取写锁,且写锁与读锁互斥。

使用示例

// 获取读写锁
RReadWriteLock rwLock = redissonClient.getReadWriteLock("product:info:1001");// 1. 读操作(获取读锁)
RLock readLock = rwLock.readLock();
try {readLock.lock(5, TimeUnit.SECONDS);System.out.println("获取读锁,查询商品详情..."); // 多个线程可同时执行
} finally {readLock.unlock();
}// 2. 写操作(获取写锁)
RLock writeLock = rwLock.writeLock();
try {writeLock.lock(5, TimeUnit.SECONDS);System.out.println("获取写锁,更新商品库存..."); // 仅一个线程执行
} finally {writeLock.unlock();
}

(3)联锁(RMultiLock)

        需同时获取多个锁,全部获取成功才继续执行,适用于 “多资源协同锁定” 场景(如转账需同时锁定付款方和收款方账户)。使用示例

// 1. 获取两个独立的锁
RLock lock1 = redissonClient.getLock("account:lock:1001"); // 付款方账户锁
RLock lock2 = redissonClient.getLock("account:lock:1002"); // 收款方账户锁// 2. 创建联锁(需全部锁获取成功才生效)
RMultiLock multiLock = new RedissonMultiLock(lock1, lock2);try {// 3. 尝试获取联锁(等待3秒,持有5秒)if (multiLock.tryLock(3, 5, TimeUnit.SECONDS)) {System.out.println("获取所有锁成功,执行转账逻辑...");}
} finally {if (multiLock != null && multiLock.isHeldByCurrentThread()) {multiLock.unlock();}
}

(4)红锁(RRedLock)

        在多个独立 Redis 节点(非集群,避免集群脑裂)上获取锁,超过半数节点获取成功即视为锁获取成功,适用于对锁可用性要求极高的场景(如金融交易),避免单点 Redis 故障导致锁失效。使用示例

// 1. 在3个独立Redis节点上创建锁
RLock lock1 = redissonClient.getLock("order:pay:1001"); // 节点1
RLock lock2 = redissonClient.getLock("order:pay:1001"); // 节点2(需单独配置RedissonClient)
RLock lock3 = redissonClient.getLock("order:pay:1001"); // 节点3// 2. 创建红锁(超过半数节点成功即生效)
RRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);try {if (redLock.tryLock(3, 5, TimeUnit.SECONDS)) {System.out.println("红锁获取成功,执行支付逻辑...");}
} finally {if (redLock != null && redLock.isHeldByCurrentThread()) {redLock.unlock();}
}

Redisson 示例

        请参考项目地址中 springboot-lock/springboot-distributed-lock 模块代码。

Redisson 注意

1. 锁 Key 设计:保证唯一性

        锁 Key 需与业务场景强绑定,避免不同业务共用一个 Key 导致锁冲突。例如:

  • 订单创建:order:create:{userId}(按用户区分,避免同一用户并发创建订单);
  • 库存扣减:stock:deduct:{productId}(按商品区分,避免不同商品库存锁冲突)。

2. 安全释放锁:避免释放他人锁

  • 必须在 finally 中释放锁,确保业务异常时锁仍能释放;
  • 释放前通过 isHeldByCurrentThread() 判断当前线程是否持有锁,避免释放其他线程的锁(如线程 A 超时未释放,锁被自动过期,线程 B 获取锁后,线程 A 恢复执行释放了线程 B 的锁)。

3. 锁粒度:尽量减小锁范围

        避免将整个业务流程加锁,仅对 “共享资源修改” 的核心逻辑加锁,减少锁持有时间,提高并发效率。

4. Redis 高可用:避免锁服务单点故障

        分布式锁依赖 Redis,需确保 Redis 高可用:

  • 开发环境:单机 Redis(带持久化,避免重启丢失锁);
  • 生产环境:Redis 集群(3 主 3 从)或哨兵模式,避免单点 Redis 宕机导致锁不可用。

5. 序列化配置:避免特殊字符问题

        Redisson 默认使用 JDK 序列化,可能导致 Redis 中存储的 Key/Value 包含特殊字符(如 \xAC\xED),建议改为 Jackson 序列化,提高可读性。

Redisson 对比

特性原生 Redis 锁(setNx+expire)Redisson 分布式锁
重入性不支持(需手动维护线程标识和重入次数)原生支持(RLock)
自动续期不支持(需手动定时任务续期)支持(Watch Dog 机制)
锁释放安全可能释放他人锁(需手动判断线程标识)自动判断当前线程,安全释放
锁类型仅基础互斥锁支持公平锁、读写锁、联锁、红锁等
易用性需手动封装(原子操作、异常处理)开箱即用,API 简洁

        显然,Redisson 解决了原生 Redis 锁的所有痛点,是 Spring Boot 3 分布式系统中实现分布式锁的最优选择

总结

        在生产环境中,只需关注 “锁 Key 设计”“锁粒度控制”“Redis 高可用” 三个核心点,即可安全、高效地使用 Redisson 分布式锁解决并发问题。Redisson 为 Spring Boot 3 提供了 “开箱即用” 的分布式锁解决方案,核心优势包括:

  1. 支持多种锁类型(可重入锁、公平锁、读写锁等),满足不同业务场景;
  2. 内置 Watch Dog 自动续期,避免业务未完成锁过期;
  3. 封装原子操作和异常处理,简化开发;
  4. 支持 Redis 所有部署模式,保证高可用。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 Tkinter + Requests 实现地理信息安全系统学习时长助手

✨重磅!盹猫的个人小站正式上线啦~诚邀各位技术大佬前来探秘!✨ 这里有: 硬核技术干货:编程技巧、开发经验、踩坑指南,带你解锁技术新姿势!趣味开发日常:代码背后的脑洞故事、工具…

构建一个优雅的待办事项应用:现代JavaScript实践

构建一个优雅的待办事项应用:现代JavaScript实践本文将介绍如何使用现代JavaScript(ES6)和DOM操作创建一个功能完整的待办事项应用,无需任何外部库或框架。功能概述添加新任务标记任务为完成/未完成编辑任务内容删除任务过滤任务&…

【数据可视化-111】93大阅兵后的军费开支情况———2024年全球军费开支分析:用Python和Pyecharts打造炫酷可视化大屏

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

3.2.Maven-概述-介绍安装

一.介绍:二.安装:Maven的安装比较简单,因为他是绿色版的软件,官方给我们提供Maven的安装包就是一个zip压缩包,在进行Maven安装以及配置的时候,主要进行如下4步操作:第一步:把官方提供…

Kafka面试精讲 Day 14:集群扩容与数据迁移

【Kafka面试精讲 Day 14】集群扩容与数据迁移 在“Kafka面试精讲”系列的第14天,我们将深入探讨 Kafka 运维中最关键的操作之一:集群扩容与数据迁移。随着业务增长,原始 Kafka 集群可能面临磁盘不足、吞吐瓶颈或节点负载不均等问题&#xff…

字节一面 面经(补充版)

什么是RabbitMQ,特点是什么怎么理解保障消息的一致性String、StringBuffer、StringBuilder解释一下线程安全先操作数据库再删缓存还是先删缓存再操作数据库这种办法能杜绝数据不一致问题吗解释一下AOP介绍Redis的特点(Redis比较快)Redis为什么…

【MFC】对话框属性:Absolute Align(绝对对齐)

前言 本文介绍对话框属性中的Absolute Align(绝对对齐),同时给出相关示例便于理解。 目录1 位置2 详解3 示例1 位置 首先介绍一下这个属性在哪里。 在资源视图中双击对话框节点,打开该对话框; 鼠标右键工作区空白处,单击属性&…

【从0开始学习Java | 第17篇】集合(中-Set部分)

文章目录Java集合之Set:无序不重复的元素容器一、Set接口的核心特性二、常用实现类及底层原理1. HashSet:基于哈希表的高效实现2. LinkedHashSet:保留插入顺序的哈希实现3. TreeSet:基于红黑树的排序实现三、实现类对比与选择建议…

玩转Docker | 使用Docker部署dufs文件管理工具

玩转Docker | 使用Docker部署dufs文件管理工具 前言 一、 dufs介绍 Dufs简介 核心特性 📁 静态文件服务 💾 文件夹打包下载 📤 拖拽上传文件/文件夹 ✏️ 文件在线创建、编辑与搜索 ⏳ 断点续传与部分传输 🔐 细粒度访问控制 🔒 HTTPS 安全传输 🌐 WebDAV 兼容支持…

【混合开发】vue+Android、iPhone、鸿蒙、win、macOS、Linux之android 把assert里的dist.zip 包解压到sd卡里

一图胜千言 上一篇有 <!-- 读写外部存储 --> <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion"28"/> <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE&qu…

线程的创建.销毁

线程线程的创建在 C 中&#xff0c;线程的创建核心是通过std::thread类实现的&#xff0c;其构造函数需要传入一个可调用对象&#xff08;Callable Object&#xff09;作为线程入口。可调用对象包括普通函数、lambda 表达式、函数对象&#xff08;functor&#xff09;、类的成员…

MySQL基础全面解析

MySQL作为最流行的关系型数据库管理系统之一&#xff0c;是每一位开发者必备的核心技能。本文将系统性地解析MySQL的基础知识&#xff0c;结合关键概念与实战应用&#xff0c;帮助您构建扎实的数据库基础。1. SQL与NoSQL的本质区别SQL&#xff08;结构化查询语言&#xff09;数…

4、幽络源微服务项目实战:后端公共模块创建与引入多租户模块

前言 上节我们将电网巡检系统的前端vue2项目创建、配置&#xff0c;并构建了最基础的多租户界面&#xff0c;本节来继续构建后端的公共模块、多租户模块&#xff0c;并将公共模块引入到多租户模块中。 创建公共模块和多租户模块 在back父工程下创建两个Module&#xff0c;和…

STM32学习路线开启篇:芯片简介与课程简介

编写不易,请多多指教,觉得不错可以关注一下,相互学习 前言 一、课程配套资源 1、面包板 2、面包板专用的跳线 3、面包板的飞线 4、杜邦线 5、STM32F103C8T6最小系统板 6、0.96寸的OLED显示屏模块 7、电位器 8、按钮 9、LED灯 10、STLINK 11、USB转串口(TTL)模块 12、源蜂鸣器模…

图像直方图

图像直方图就是用来统计图像像素值分布的。灰度图分布读取灰度图phone cv2.imread(phone.png, cv2.IMREAD_GRAYSCALE) a phone.ravel() plt.hist(a, bins256) plt.show()如何可以获得当前像素值分布读取各通道的像素值分布img cv2.imread(phone.png) colors (b, g, r) for …

分类别柱状图(Vue3)

效果图&#xff1a;需求&#xff1a;男女年龄段占比<template><div class"go-ClassifyBar01"><v-chartref"vChartRef":option"option"style"width: 100%; height: 800px"></v-chart></div> </templa…

Apache Dubbo学习笔记-使用Dubbo发布、调用服务

Apache Dubbo经常作为一个RPC框架来使用&#xff0c;这篇文章主要介绍使用Dubbo配合注册中心来发布和调用服务。 Apache Dubbo和Spring Boot、JDK的版本对应关系。 Dubbo 分支最新版本JDKSpring Boot组件版本详细说明3.3.x (当前文档)3.3.08, 17, 212.x、3.x详情- 版本变更记录…

Python学习——字典和文件

前面python的学习中我们已经学习了python的函数和列表元组相关的内容&#xff0c;接下来我们来学习剩下的python语法&#xff1a;字典和文件 相关代码已经上传到作者的个人gitee&#xff1a;楼田莉子/Python 学习喜欢请点个赞谢谢 目录 字典 创建字典 查找key 新增/修改元素 …

swiper插件的使用

官方网址&#xff1a;https://www.swiper.com.cn/ 1、点击导航栏&#xff0c;获取Swiper里边的下载Swiper 2、选择要下载的版本【本次案例版本5.4.5】&#xff0c;然后解压缩文件夹&#xff0c;拿到swiper.min.js和swiper.min.css文件&#xff0c;放到项目对应的css文件和js文…

Vue3+JS 组合式 API 实战:从项目痛点到通用 Hook 封装

Vue3 组合式 API 的实战技巧 —— 组合式 API 帮我解决了不少 Options API 难以应对的问题&#xff0c;尤其是在代码复用和复杂组件维护上。一、为什么放弃 Options API&#xff1f;聊聊三年项目里的真实痛点​刚接触 Vue3 时&#xff0c;我曾因 “惯性” 继续用 Options API 写…