Spring自带分布式锁你用过吗?

环境:SpringBoot2.7.12

本篇文章将会为大家介绍有关spring integration提供的分布式锁功能。

1. 简介

Spring Integration 是一个框架,用于构建事件驱动的应用程序。在 Spring Integration 中,LockRegistry 是一个接口,用于管理分布式锁。分布式锁是一种同步机制,用于确保在分布式系统中的多个节点之间对共享资源的互斥访问。

LockRegistry及相关子接口(如:RenewableLockRegistry) 接口的主要功能:

  • 获取锁:当应用程序需要访问共享资源时,它可以通过 LockRegistry 获取一个锁。
  • 释放锁:当应用程序完成对共享资源的访问后,它应该释放锁,以便其他应用程序可以获取它(第一点中提到,并没有提供直接释放锁的操作,而是内部自动完成)。
  • 续期:提供续期机制,以便在需要时延长锁的持有时间。

常见的 LockRegistry 实现包括基于数据库、ZooKeeper 和 Redis 的实现。

公共依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-integration</artifactId>
</dependency>

2. 基于数据库分布式锁

引入依赖

<dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-jdbc</artifactId>
</dependency>
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><scope>compile</scope>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version>
</dependency>

配置

spring:datasource:driverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/spring_lock?serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&useSSL=falseusername: rootpassword: xxxoootype: com.zaxxer.hikari.HikariDataSourcehikari:minimumIdle: 10maximumPoolSize: 200
---
spring:integration:jdbc:initialize-schema: always# 基于数据库需要执行初始化脚本schema: classpath:schema-mysql.sql

注册核心Bean对象

@Bean
public DefaultLockRepository defaultLockRepository(DataSource dataSource) {DefaultLockRepository lockRepository = new DefaultLockRepository(dataSource);// 这里根据你的业务需要,配置表前缀,默认:IN_lockRepository.setPrefix("T_") ;return lockRepository ;
}// 注册基于数据库的分布式锁
@Bean
public JdbcLockRegistry jdbcLockRegistry(DefaultLockRepository lockRepository) {return new JdbcLockRegistry(lockRepository) ;
}

测试用例

@Test
public void testLock() throws Exceptionint len = 10 ;CountDownLatch cdl = new CountDownLatch(len) ;CountDownLatch waiter = new CountDownLatch(len) ;Thread[] ts = new Thread[len] ;for (int i = 0; i < len; i++) {ts[i] = new Thread(() -> {waiter.countDown() ;System.out.println(Thread.currentThread().getName() + " - 准备获取锁") ;try {waiter.await() ;} catch (InterruptedException e1) {e1.printStackTrace();}// 获取锁Lock lock = registry.obtain("drug_store_key_001") ;lock.lock() ;System.out.println(Thread.currentThread().getName() + " - 获取锁成功") ;try {try {TimeUnit.SECONDS.sleep(2) ;} catch (InterruptedException e) {e.printStackTrace();}} finally {// 释放锁lock.unlock() ;cdl.countDown() ;System.out.println(Thread.currentThread().getName() + " - 锁释放成功") ;}}, "T - " + i) ;}for (int i = 0; i < len; i++) {ts[i].start() ; }cdl.await() ;
}

数据库

图片

锁的实现JdbcLock,该对象实现了java.util.concurrent.locks.Lock,所以该锁是支持重入等操作的。

配置锁获取失败后的重试间隔,默认值100ms

JdbcLockRegistry jdbcLockRegistry = new JdbcLockRegistry(lockRepository);
// 定义锁对象时设置当获取锁失败后重试间隔时间。
jdbcLockRegistry.setIdleBetweenTries(Duration.ofMillis(200)) ;

锁续期

jdbcLockRegistry.renewLock("drug_store_key_001");

3. 基于Redis分布式锁

引入依赖

<dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-jdbc</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置

spring:redis:host: localhostport: 6379password: xxxooodatabase: 8lettuce:pool:maxActive: 8maxIdle: 100minIdle: 10maxWait: -1

测试用例

测试代码与上面基于JDBC的一样,只需要修改调用加锁的代码即可

Lock lock = redisLockRegistry.obtain("001") ;

设置锁的有效期,默认是60s

// 第三个参数设置了key的有效期,这里改成10s
RedisLockRegistry redisLockRegistry = new RedisLockRegistry(connectionFactory, registryKey, 10000) ;

注意:redis key的有效期设置为10s,如果你的业务执行超过了10s,那么程序将会报错。并没有redission watch dog机制。

Exception in thread "T - 0" java.lang.IllegalStateException: Lock was released in the store due to expiration. The integrity of data protected by this lock may have been compromised.at org.springframework.integration.redis.util.RedisLockRegistry$RedisLock.unlock(RedisLockRegistry.java:450)at com.pack.SpringIntegrationDemoApplicationTests.lambda$1(SpringIntegrationDemoApplicationTests.java:83)at java.lang.Thread.run(Thread.java:748)

如果10s过期后key自动删除后,其它线程是否能立马获取到锁呢?如果是单节点中其它现在也不能获取锁,必须等上一个线程结束后才可以,这是因为在内部还维护了一个ReentrantLock锁,在获取分布式锁前要先获取本地的一个锁。

private abstract class RedisLock implements Lock {private final ReentrantLock localLock = new ReentrantLock();public final void lock() {this.localLock.lock();while (true) {try {if (tryRedisLock(-1L)) {return;}} catch (InterruptedException e) {} catch (Exception e) {this.localLock.unlock();rethrowAsLockException(e);}}}
}

注意:不管是基于数据库还是Redis都要先获取本地的锁

Spring Cloud Task就使用到了Spring Integration中的锁基于数据库的。

总结:Spring Integration 的分布式锁为开发者提供了一种在分布式系统中实现可靠同步的有效方法。通过合理选择和使用这些锁实现,可以确保对共享资源的访问在多个节点之间保持协调一致,从而提高系统的整体可靠性和性能。

完毕!!!

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

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

相关文章

使用Postman测试WebService接口

文章目录 使用Postman测试WebService接口1. 访问wsdl地址2. Postman配置1. URL及Headers设置2. Body设置3. 响应结果 使用Postman测试WebService接口 1. 访问wsdl地址 接口地址如&#xff1a;http://localhost:8101/ws/hello?wsdl 2. Postman配置 1. URL及Headers设置 2. B…

跟着小德学C++之数据库基础

嗨&#xff0c;大家好&#xff0c;我是出生在达纳苏斯的一名德鲁伊&#xff0c;我是要立志成为海贼王&#xff0c;啊不&#xff0c;是立志成为科学家的德鲁伊。最近&#xff0c;我发现我们所处的世界是一个虚拟的世界&#xff0c;并由此开始&#xff0c;我展开了对我们这个世界…

【揭秘】sleep()、wait()、park()三种休眠方式的终极对比

在Java中&#xff0c;线程休眠的三种方式包括Thread.sleep、Object.wait和LockSupport.park。Thread.sleep使线程在指定时间后进入休眠&#xff0c;状态为TIMEDWAITING&#xff0c;不会释放锁。Object.wait需在对象锁的保护下调用&#xff0c;会释放该对象的锁&#xff0c;使线…

leetcode 动态规划(单词拆分)

139.单词拆分 力扣题目链接(opens new window) 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict&#xff0c;判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 说明&#xff1a; 拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。 …

图解智慧:数据可视化如何助你高效洞悉信息?

在信息爆炸的时代&#xff0c;数据扮演着越来越重要的角色&#xff0c;而数据可视化则成为解读和理解海量数据的得力工具。那么&#xff0c;数据可视化是如何帮助我们高效了解数据的呢&#xff1f;下面我就以可视化从业者的角度来简单聊聊这个话题。 无需深奥的专业知识&#x…

第1章 数据结构与算法介绍

文章目录 1.1 数据结构和算法内容介绍1.1.1 先看几个经典的算法面试题1.1.2 数据结构和算法的重要性1.1.3 本套数据结构和算法内容介绍1.1.4 课程亮点和授课方式 1.1 数据结构和算法内容介绍 1.1.1 先看几个经典的算法面试题  字符串匹配问题&#xff1a;&#xff1a; 有一…

wpf使用Popup封装数据筛选框

(关注博主后,在“粉丝专栏”,可免费阅读此文) 类似于DevExpress控件的功能 这是DevExpress的winform筛选样式,如下: 这是DevExpress的wpf筛选样式,如下: 这是Excel的筛选样式,如下: 先看效果 本案例使用wpf原生控件封装,功能基本上都满足,只是颜色样式没有写…

为何我选择山海鲸可视化:五大优势解析

在众多的可视化产品中&#xff0c;我选择了山海鲸可视化&#xff0c;这并非偶然。在对比了其他同类产品后&#xff0c;我发现山海鲸可视化具有许多独特的优势和特点&#xff0c;使得它成为了我心目中的理想选择。下面我简单说一下我选择这款产品的几大原因&#xff0c;希望对在…

最新国内可用GPT4、Midjourney绘画、DALL-E3文生图模型教程

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…

【python 的各种模块】(9) 在python使用PIL( 即pillow模块 ) 修改图片

目录 1 导入PIL模块&#xff08;pillow&#xff09; 1.1 PIL的全称&#xff1a;Python Imaging Library 1.2 导入PIL模块 1.2.1 可用的导入形式 1.2.2 常用的导入形式 1.2.3 PIL下面的常用子模块 2 PIL.Image的方法 (读入&#xff0c;生成和显示图片) 2.1 用 PIL.Image…

蓝桥杯AcWing学习笔记 8-2数论的学习(下)

蓝桥杯 我的AcWing 题目及图片来自蓝桥杯C AB组辅导课 数论&#xff08;下&#xff09; 蓝桥杯省赛中考的数论不是很多&#xff0c;这里讲几个蓝桥杯常考的知识点。 约数个数定理 我们如何去求一个数的约数个数呢&#xff1f; N N N分解质因数的结果&#xff1a; N P 1 α…

HTML+CSS-02

阿里巴巴矢量图标库的使用 阿里巴巴网址矢量图标库网址 https://www.iconfont.cn/ 如何使用 选择需要的icon图标加入购物车下载代码 在将解压后的文件夹复制到项目中进入demo_index.html中打开就可以看到示例的三种用法 三种引入方法 Unicode 引用 Unicode 是字体在网页端…

vscode(visual studio code) 免密登陆服务器

1.生成密钥 首先&#xff0c;在本地&#xff0c;打开命令输入框&#xff1a; WinR–>弹出输入框&#xff0c;输入cmd,打开命令框。 然后&#xff0c;在命令框&#xff0c;输入 ssh-keygen -t rsa -C "love"按两次回车键&#xff0c;问你是否重写&#xff0c;选择…

人工智能SCI二区期刊Applied Intelligence高被引录用论文合集,含2024最新

今天给着急发论文的同学推荐一本期刊&#xff1a;《APPLIED INTELLIGENCE》。 该刊由SPRINGER出版商于1991年创刊&#xff0c;刊期Bimonthly&#xff0c;专注于人工智能和神经网络的研究&#xff0c;重点关注有关创新智能系统的方法论及其在解决现实生活复杂问题的研究进展&am…

Springboot中使用Filter过滤器

1、概述 springboot工程中使用Filter过滤器与其他地方使用基本相同&#xff0c;只是注入的方式不同。 2、创建Filter过滤器 实现Filter接口&#xff0c;重写doFilter方法 filterChain.doFilter(servletRequest,servletResponse);表示放行 public class MyFilter implement…

Rocketmq rust版本-开篇

我是蚂蚁背大象(Apache EventMesh PMC&Committer)&#xff0c;文章对你有帮助给Rocketmq-rust star,关注我GitHub:mxsm&#xff0c;文章有不正确的地方请您斧正,创建ISSUE提交PR~谢谢! Emal:mxsmapache.com Rust重构Rocketmq,大家好我是mxsm(Apache EventMesh PMC&Comm…

基于SSM的网上订餐管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

go语言初探(一)

package mainimport ("fmt""time" )func main() {fmt.Print("hello go!")time.Sleep(1 * time.Second)}运行后&#xff0c;结果如下&#xff1a; 1、golang表达式中&#xff0c;加&#xff1b;和不加&#xff1b;都可以 2、函数的{和函数名一…

五、Model与View

一、Model/View结构 数据&#xff1a;如数据库的一个数据表或者SQL查询结果&#xff0c;如内存中的数据类对象&#xff0c;或者磁盘文件结构等Model&#xff1a;与数据通信&#xff0c;并作为视图组件提供数据接口View&#xff1a;屏幕界面组件&#xff0c;视图从数据模型获得…

软件工程:黑盒测试等价分类法相关知识和多实例分析

目录 一、黑盒测试和等价分类法 1. 黑盒测试 2. 等价分类法 二、黑盒测试等价分类法实例分析 1. 工厂招工年龄测试 2. 规定电话号码测试 3. 八位微机测试 4. 三角形判断测试 一、黑盒测试和等价分类法 1. 黑盒测试 黑盒测试就是根据被测试程序功能来进行测试&#xf…