Spring Boot牵手Redisson:分布式锁实战秘籍

一、引言

在这里插入图片描述

在当今的分布式系统架构中,随着业务规模的不断扩大和系统复杂度的日益增加,如何确保多个服务节点之间的数据一致性和操作的原子性成为了一个至关重要的问题。在单机环境下,我们可以轻松地使用线程锁或进程锁来控制对共享资源的访问,但在分布式系统中,由于各个服务节点分布在不同的物理或逻辑位置,它们之间的内存并不共享,传统的锁机制无法直接应用。这时候,分布式锁应运而生。

分布式锁作为一种跨节点的同步机制,能够有效地控制多个进程或线程对共享资源的访问,确保在同一时刻只有一个客户端能够获取到锁并执行临界区代码,从而避免数据不一致和竞态条件等问题。它在许多场景中都发挥着关键作用,比如电商系统中的库存扣减、订单处理,分布式任务调度系统中的任务分配与执行,以及缓存数据的更新等。

在众多分布式锁的实现方案中,基于 Redis 的方案因其高性能、简单易用等特点而被广泛采用。而 Redisson 作为一个在 Redis 基础上实现的 Java 驻内存数据网格(In-Memory Data Grid),不仅提供了对 Redis 各种数据结构的便捷访问接口,还封装了一系列分布式系统常用的高级功能,其中就包括功能强大、易于使用的分布式锁实现。

Spring Boot 则是当前最流行的 Java 开发框架之一,它通过自动配置和约定大于配置的理念,极大地简化了 Spring 应用的开发过程,使得开发者能够快速搭建出高效、稳定的应用程序。

将 Redisson 与 Spring Boot 进行集成,能够充分发挥两者的优势,为我们提供一种简单、高效的分布式锁解决方案。在本文中,我们将深入探讨如何在 Spring Boot 项目中集成 Redisson 来实现分布式锁,并通过实际的代码示例和详细的解释,帮助大家理解其原理和使用方法,同时也会分享一些在实际应用中可能遇到的问题及解决方案 。

二、认识 Redisson 与分布式锁

2.1 Redisson 简介

Redisson 是一个基于 Redis 的 Java 驻内存数据网格(In-Memory Data Grid)和分布式锁服务。它不仅仅是对 Redis 的简单封装,更是提供了一系列丰富的分布式 Java 数据结构和服务,使得在 Java 应用中使用 Redis 变得更加便捷和强大。Redisson 支持多种 Redis 的部署模式,包括单节点、集群、哨兵和主从模式,这使得它能够适应各种不同规模和复杂度的分布式系统。

在 Redisson 中,你可以像使用本地 Java 对象一样使用各种分布式数据结构,如分布式集合(RSetRListRMap等)、分布式队列(RQueueRDeque等)、分布式锁(RLockRReadWriteLock等)以及分布式原子变量(RAtomicLongRAtomicDouble等)。这种高度的抽象和封装极大地简化了分布式系统的开发过程,让开发者可以专注于业务逻辑的实现,而无需过多关注底层的分布式细节。

例如,在使用 Redisson 的分布式锁时,开发者只需要通过简单的RLock lock = redisson.getLock("myLock"); lock.lock();就可以获取一个分布式锁,而无需手动编写复杂的 Redis 命令和逻辑来实现锁的获取、释放以及锁的过期处理等功能 。

2.2 分布式锁的作用

在分布式系统中,多个节点(如不同的服务器、进程或线程)可能会同时访问和操作共享资源,如数据库中的数据、缓存中的数据或者文件系统中的文件等。如果没有有效的同步机制,就可能会出现数据不一致、竞态条件(Race Condition)等问题。分布式锁的作用就是解决这些问题,它通过一种跨节点的同步机制,确保在同一时刻只有一个客户端能够获取到锁并执行临界区代码,从而避免多个客户端同时对共享资源进行并发访问和修改,保证数据的一致性和完整性。

以电商系统中的库存扣减为例,如果没有分布式锁,当多个用户同时下单购买同一件商品时,可能会出现多个订单同时扣减库存的情况,导致库存数量出现负数,从而引发超卖问题。而使用分布式锁后,只有获取到锁的订单处理线程能够执行库存扣减操作,其他线程需要等待锁的释放,这样就可以确保库存扣减操作的原子性和正确性,避免超卖现象的发生 。

2.3 常见分布式锁实现方式对比

在分布式系统中,除了基于 Redis + Redisson 实现分布式锁外,还有其他常见的实现方式,如基于 MySQL、ZooKeeper 等。下面我们来对比一下这几种实现方式的优缺点:

MySQL 实现分布式锁:利用 MySQL 的表锁或行锁机制,通过在数据库中创建一个锁表,使用唯一索引或FOR UPDATE语句来实现分布式锁。这种方式的优点是对于已经使用 MySQL 的系统来说,不需要引入额外的中间件,实现相对简单。然而,它的缺点也很明显,由于数据库的读写操作性能相对较低,在高并发场景下,会对数据库造成较大的压力,容易成为性能瓶颈。同时,数据库的可用性也会影响分布式锁的可靠性,如果数据库出现故障,整个分布式锁机制将无法正常工作 。

ZooKeeper 实现分布式锁:ZooKeeper 是一个分布式协调服务,它利用其节点的特性来实现分布式锁。客户端通过在 ZooKeeper 中创建临时顺序节点来竞争锁,并且可以通过监听节点的变化来实现锁的等待和通知机制。ZooKeeper 实现的分布式锁具有较高的可靠性和一致性,能够保证锁的公平性,即按照请求锁的顺序依次获取锁。但是,ZooKeeper 的性能相对 Redis 来说较低,因为它需要进行网络通信和节点的创建、删除等操作,这会带来一定的延迟。此外,ZooKeeper 的部署和维护相对复杂,需要搭建集群来保证高可用性 。

Redis 实现分布式锁:Redis 是一个高性能的内存数据库,它利用SET命令的NX(Not eXists)和PX(过期时间)选项来实现锁的原子获取,通过DEL命令来释放锁。Redis 实现分布式锁的优点是性能高,获取锁和释放锁的操作非常快,因为它是基于内存操作的。同时,Redis 支持锁的自动过期,这可以有效降低死锁的风险。然而,原生的 Redis 分布式锁实现不是真正意义上的公平锁,无法保证请求锁的顺序。在 Redis 集群模式下,由于数据的分布式存储和同步机制,没有内置的分布式锁支持,需要更为复杂的实现来保证锁的一致性 。

而 Redis + Redisson 的组合则充分发挥了 Redis 的高性能和 Redisson 的丰富功能与便捷性。Redisson 对 Redis 的分布式锁进行了封装和扩展,提供了更高级的锁功能,如可重入锁、公平锁、读写锁等,并且在 Redisson 的实现中,已经考虑了各种复杂的分布式场景和异常情况,使得分布式锁的使用更加安全和可靠。同时,Redisson 的 API 设计简洁易用,大大降低了开发者使用分布式锁的难度 。

三、Spring Boot 集成 Redisson 的步骤

3.1 创建 Spring Boot 项目

如果你是创建全新的 Spring Boot 项目,可以使用 Spring Initializer 来快速搭建项目骨架。打开你的 IDE(如 IntelliJ IDEA、Eclipse 等),在创建新项目时选择 Spring Initializer 选项。在向导中,填写项目的基本信息,如 Group、Artifact、Name 等,然后选择你需要的依赖,这里我们至少需要添加 Spring Web 依赖,方便后续进行测试。

如果你是在现有项目中集成 Redisson,确保项目已经是一个 Spring Boot 项目,并且已经配置好了基本的 Spring 依赖和项目结构 。

3.2 添加 Redisson 依赖

在项目的pom.xml文件中添加 Redisson 的依赖。如果你使用的是 Maven,添加以下依赖:

<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.19.3</version>
</dependency>

在选择 Redisson 版本时,要注意其与 Spring Boot 以及 Redis 的版本兼容性。可以参考 Redisson 官方文档或者相关的版本兼容性对照表,以确保选择的版本能够稳定运行。例如,Spring Boot 2.5.x 版本建议搭配 Redisson 3.16.x 系列版本 。

3.3 配置 Redisson

application.propertiesapplication.yml文件中配置 Redis 的连接信息。如果使用application.properties,配置如下:

# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器端口
spring.redis.port=6379
# Redis密码(如果有)
spring.redis.password=
# 连接超时时间(毫秒)
spring.redis.timeout=3000

如果使用application.yml,配置如下:

spring:redis:host: 127.0.0.1port: 6379password: timeout: 3000

这些配置将被redisson-spring-boot-starter自动读取并用于创建 Redisson 客户端连接。如果 Redis 部署在集群环境或者使用了哨兵模式,还需要相应地调整配置 。

3.4 编写配置类(可选)

如果你使用的是redisson-spring-boot-starter,通常不需要额外编写配置类,因为 Starter 会自动进行配置。但如果有一些特殊的配置需求,比如自定义 Redisson 的线程池大小、编解码器等,或者你没有使用 Starter 方式集成 Redisson,就需要编写配置类来创建RedissonClient实例。

以下是一个配置类的示例:

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RedissonConfig {@Bean(destroyMethod = "shutdown")public RedissonClient redissonClient() {Config config = new Config();// 使用单机模式连接Redisconfig.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("");return Redisson.create(config);}
}

在这个配置类中,我们创建了一个RedissonClient实例,并将其注册为 Spring 的 Bean。destroyMethod = "shutdown"指定了在 Spring 容器关闭时,自动调用RedissonClientshutdown方法来释放资源 。

3.5 测试集成是否成功

编写一个简单的测试代码来验证 Redisson 是否集成成功。可以创建一个 Spring 的 Service 类,在其中注入RedissonClient,并进行一些简单的操作,如获取一个分布式锁或者操作一个分布式集合。

以下是一个测试获取分布式锁的示例:

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class RedissonTestService {@Autowiredprivate RedissonClient redissonClient;public void testLock() {// 获取一个名为"myLock"的分布式锁RLock lock = redissonClient.getLock("myLock");try {// 尝试获取锁,这里可以设置等待时间和锁的过期时间boolean isLocked = lock.tryLock(10, 60, java.util.concurrent.TimeUnit.SECONDS);if (isLocked) {// 获取到锁,执行临界区代码System.out.println("成功获取到锁,执行临界区代码");// 模拟业务逻辑处理Thread.sleep(3000);} else {// 未获取到锁System.out.println("未能获取到锁");}} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁if (lock.isHeldByCurrentThread()) {lock.unlock();System.out.println("锁已释放");}}}
}

然后可以在测试类中调用这个方法进行测试:

import org.junit.jupiter.api.

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

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

相关文章

apache-poi导出excel数据

excel导出 自动设置宽度&#xff0c;设置标题框&#xff0c;设置数据边框。 excel导出 添加依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></dependency>…

畅游Diffusion数字人(16):由音乐驱动跳舞视频生成

畅游Diffusion数字人(0):专栏文章导航 前言:从Pose到跳舞视频生成的工作非常多,但是还没有直接从音乐驱动生成的工作。最近字节跳动提出了MuseDance,无需复杂的动作引导输入(如姿势或深度序列),从而使不同专业水平的用户都能轻松进行灵活且富有创意的视频生成。 目录 贡…

Kokoro 开源文本转语音引擎上线!多语言支持,无需联网,浏览器内极速运行

Kokoro 是一款轻量级的开源文本转语音(TTS)引擎,凭借其高效能和轻量化设计,迅速在技术社区中引起关注。本文将详细介绍 Kokoro 的主要特点,并提供在浏览器和 Python 环境中的代码示例,帮助您快速上手。 1. Kokoro:可在浏览器中运行的 TTS 引擎 1.1 简介 Kokoro 是一个…

人工智能学习(七)之神经网络

目录 一、引言 二、经典神经网络回顾 &#xff08;一&#xff09;结构与计算过程 &#xff08;二&#xff09;局限性 三、循环神经网络&#xff08;RNN&#xff09;原理 &#xff08;一&#xff09;基本结构 &#xff08;二&#xff09;计算过程 &#xff08;三&#xf…

在Java中操作Redis

4.在Java中操作Redis 4.1 Redis的Java客户端 前面我们讲解了Redis的常用命令&#xff0c;这些命令是我们操作Redis的基础&#xff0c;那么我们在java程序中应该如何操作Redis呢&#xff1f;这就需要使用Redis的Java客户端&#xff0c;就如同我们使用JDBC操作MySQL数据库一样。…

大语言模型需要的可观测性数据的关联方式

可观测性数据的关联方式及其优缺点 随着现代分布式架构和微服务的普及&#xff0c;可观测性&#xff08;Observability&#xff09;已经成为确保系统健康、排查故障、优化性能的重要组成部分。有效的可观测性数据关联方式不仅能够帮助我们实时监控系统的运行状态&#xff0c;还…

棱光PDF工具箱:一站式解决你的各种需要

今天为大家介绍一款非常实用且完全免费的PDF工具箱——棱光PDF工具箱。它功能强大&#xff0c;操作简单&#xff0c;能够满足你对PDF文件的各种处理需求&#xff0c;包括添加水印、去除水印、批量转换格式等&#xff0c;绝对值得推荐&#xff01; 棱光PDF工具箱 棱光PDF工具箱…

Docker安装Redis

一、保证Docker提起来了 systemctl status docker想这没有启动要先启动一下 systemctl status docke二、拉取Redis&#xff08;默认拉最新版&#xff09; sudo docker pull redis检查一下拉成功没有 docker images三、创建相关目录 mkdir -p /home/redis/{conf,data}四、…

云原生(五十四) | RDS数据导入与导出

文章目录 RDS数据导入与导出 一、导入场景说明 二、RDS数据导入实现 三、导出场景说明 四、RDS数据导出实现 RDS数据导入与导出 一、导入场景说明 思考&#xff1a;我们刚才的操作都是通过SQL语句实现的&#xff0c;如果我们要导入的文件是以SQL、CSV或Excel等形式存储&…

如何使用DeepSeek帮助自己的工作?

最近众多大模型爆火,如日中天的,莫过于最近的DeepSeek了,那么怎么去利用它帮助我们的工作呢? 代码生成与优化 快速生成代码:程序员可以直接通过自然语言描述功能需求,让 DeepSeek 生成相应的代码。比如需要实现一个用 Python 编写的计算斐波那契数列的函数,只需简单描述…

Python Pandas(3):DataFrame

1 介绍 DataFrame 是 Pandas 中的另一个核心数据结构&#xff0c;类似于一个二维的表格或数据库中的数据表。它含有一组有序的列&#xff0c;每列可以是不同的值类型&#xff08;数值、字符串、布尔型值&#xff09;。DataFrame 既有行索引也有列索引&#xff0c;它可以被看做由…

防火墙术语大全( Firewalld Glossary of Terms)

防火墙术语大全 防火墙作为网络安全中不可或缺的设备&#xff0c;在各种网络架构中扮演着至关重要的角色。无论是企业级防火墙、云防火墙还是家用路由器内置的防火墙&#xff0c;它们的工作原理和配置策略都离不开一系列专业术语的支撑。对于网络工程师来说&#xff0c;掌握这…

Web前端开发--HTML

HTML快速入门 1.新建文本文件&#xff0c;后缀名改为.html 2.编写 HTML结构标签 3.在<body>中填写内容 HTML结构标签 特点 1.HTML标签中不区分大小写 2.HTML标签属性值中可以使用单引号也可使用双引号 3.HTML语法结构比较松散&#xff08;但在编写时要严格一点&…

深度整理总结MySQL——MySQL加锁工作原理

MySQL加锁工作原理 前言前置知识- 锁为什么加在索引上锁的粒度优化提高并发性避免全表扫描优化死锁处理解决幻读问题 什么SQL语句会加行级锁MySQL是如何加行级锁场景模拟代码唯一索引等值查询退化为记录锁为什么会退化为记录锁分析加了什么锁为什么会退化为间隙锁为什么我可以插…

2.10日学习总结

题目一&#xff1a; AC代码 #include <stdio.h>#define N 1000000typedef long long l;int main() {int n, m;l s 0;l a[N 1], b[N 1];int i 1, j 1;scanf("%d %d", &n, &m);for (int k 1; k < n; k) {scanf("%lld", &a[k]);…

Spring Boot Actuator(官网文档解读)

定义 Spring Boot Actuator 是 Spring Boot 提供的一个用于监控和管理应用程序的模块。它能够提供各种生产级别的功能&#xff0c;如健康检查、度量指标收集、配置属性查看等&#xff0c;帮助开发者了解应用的内部状态并进行故障排查。 Actuator 引入 要启用 Actuator…

如何实现图片式按钮的功能

文章目录 1. 概念介绍2. 使用方法2.1 filled风格2.2 filledTonal风格2.3 outlined风格 3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"如何修改NavigationBar组件的形状"相关的内容&#xff0c;本章回中将介绍IconButtion组件.闲话休提…

[LLM面试题] 指示微调(Prompt-tuning)与 Prefix-tuning区别

一、提示调整(Prompt Tuning) Prompt Tuning是一种通过改变输入提示语&#xff08;input prompt&#xff09;以获得更优模型效果的技术。举个例子&#xff0c;如果我们想将一条英语句子翻译成德语&#xff0c;可以采用多种不同的方式向模型提问&#xff0c;如下图所示&#xf…

2月10日QT

作业> 将文本编辑器功能完善 include "widget.h" #include "ui_widget.h" #include <QMessageBox> //消息对话框类 #include <QFontDialog> //字体类对话框 #include <QFont> //字体类 #include <QColorDialog> //颜…

安卓开发,底部导航栏

1、创建导航栏图标 使用系统自带的矢量图库文件&#xff0c;鼠标右键点击res->New->Vector Asset 修改 Name , Clip art 和 Color 再创建一个 同样的方法再创建四个按钮 2、添加百分比布局依赖 app\build.gradle.kts 中添加百分比布局依赖&#xff0c;并点击Sync Now …