简单理解下基于 Redisson 库的分布式锁机制

目录

    • 简单理解下基于 Redisson 库的分布式锁机制
      • 代码流程:
        • 方法的调用:
        • 具体锁的实现:
          • riderBalance 方法:
          • tryLock 方法(重载):
          • tryLock 方法(核心实现):

在这里插入图片描述

简单理解下基于 Redisson 库的分布式锁机制

这段代码实现了一个基于 Redisson 库的分布式锁机制

Redisson 是一个基于 Redis 的 Java 客户端库,它提供了丰富的分布式数据结构和工具,旨在使 Java 开发者能够轻松地在分布式环境下使用 Redis。

Redisson 是 Redis 的高级封装,除了常规的 Redis 命令支持外,它还提供了很多额外的功能,如分布式锁、分布式集合、分布式队列、分布式缓存等,使得开发者在分布式系统中实现高效、可靠的操作。

比方对一个用户所拥有的金额进行增减操作,肯定需要上锁才能保证一定的安全性。

代码流程:

方法的调用:

一个简单的流程:

LockUtil.riderBalance(riderId, () -> {…}) 是一个加锁操作,是一种使用分布式锁来确保线程安全的机制,确保在修改 余额时,避免并发冲突。

简要来说,它的作用是在执行余额操作时,确保只有一个线程能够对指定的骑手账户进行操作,避免多个线程同时修改余额,导致数据不一致的情况。

LockUtil.riderBalance(riderId, …) 通过 riderId 获取一个锁,这样就能确保在同一时刻,只有一个线程可以执行传入的操作逻辑。

riderId 是骑手的唯一标识,通过它来加锁,防止对同一个骑手账户的并发操作。

() -> {…}: 这是一个 Lambda 表达式,表示当获得锁之后要执行的具体操作。这个操作包括:获取骑手的余额信息、执行余额扣除、记录操作日志等步骤。

    /*** 扣除余额*/@Override@Transactional(rollbackFor = Exception.class)public boolean deductionBalance(Integer riderId, BigDecimal amount, String title, Integer orderId, String orderCode, RiderCashlogType cashlogType, RiderCashlogStatus cashlogStatus) {return LockUtil.riderBalance(riderId, () -> {// 变更前RiderServiceDto riderBefore = this.getRiderById(riderId);// 减少余额 -------- ★★★★★★★★★★★★★★★★★★★★★★★★boolean flag = xxRiderService.deductionBalance(riderId, amount);// 变更后RiderServiceDto riderAfter = this.getRiderById(riderId);// 增加流水日志if (flag) {RiderCashlogServiceDto cashlog = new RiderCashlogServiceDto();cashlog.setMoneyType(RiderCashlogMoneyType.BALANCE);cashlog.setTitle(title);......return xxRiderCashlogService.addCashlog(cashlog);}return false;}, () -> {throw BizException.newInstance(ErrorCode.BUSY);});}

调用接口方法

    /*** 扣除余额*/boolean deductionBalance(Integer riderId, BigDecimal amount);

这里再进行详细的扣除方法,依然是用同个锁

    /*** 扣除余额*/@Overridepublic boolean deductionBalance(Integer riderId, BigDecimal amount) {if (amount.compareTo(BigDecimal.ZERO) == 0) {return true;}// 加锁return LockUtil.riderBalance(riderId, () -> {if (ObjectUtil.isEmpty(riderId) || amount.compareTo(BigDecimal.ZERO) < 0) {log.error("扣除xx余额失败,riderId:{},amount:{}", riderId, amount);return false;}RiderServiceDto rider = this.getRiderById(riderId);// 获取当前账号的余额BigDecimal valid = rider.getValidMoney();// 判断当前余额是否足够if (valid.compareTo(amount) < 0) {throw BizException.newInstance(ErrorCode.ARGUMENT_ERROR, "扣除余额失败,余额小于" + amount.toPlainString());}return this.update(new UpdateWrapper<RiderEntity>().lambda().eq(RiderEntity::getId, riderId).setSql("valid_money = valid_money - " + amount));}, () -> {throw BizException.newInstance(ErrorCode.BUSY);});}
具体锁的实现:
riderBalance 方法:
    /*** 锁骑手余额------* Integer riderId: 骑手的 ID,作为分布式锁的标识。* Supplier<T> supplier: 提供数据或执行操作的函数接口。*                       传入的 Supplier<T> 函数接口,用来提供需要执行的业务操作。如果获取锁成功,业务操作会在锁内部执行。* InvokeInter lockFail: 如果获取锁失败,执行的操作。*/public static <T> T riderBalance(Integer riderId, Supplier<T> supplier, InvokeInter lockFail) {return tryLock(RedisKey.LOCK_RIDER_BALANCE_XXXXX.getKey(riderId), supplier, lockFail);}
tryLock 方法(重载):
    /*** 设置分布式锁*/public static <T> T tryLock(String key, Supplier<T> supplier, InvokeInter lockFail) {//这是 tryLock 的一个重载方法,它会在尝试获取锁时默认设置超时时间为 10 秒//通过 key、supplier 和 lockFail,它会调用 tryLock 的另一个重载版本,并使用 10 秒的默认超时时间return tryLock(key, supplier, lockFail, 10, TimeUnit.SECONDS);}
tryLock 方法(核心实现):
/*** 设置分布式锁-----------* key: 锁的标识符,通常是与某个资源(如骑手余额)相关的唯一标识。* supplier: 需要执行的业务逻辑。* lockFail: 获取锁失败时的回调操作。* amount 和 unit: 锁的持有时间(amount)和时间单位(unit),用于控制获取锁的最长等待时间。*/public static <T> T tryLock(String key, Supplier<T> supplier, InvokeInter lockFail, long amount, TimeUnit unit) {//通过 Redisson 客户端获取一个 RLock 对象,RLock 是 Redisson 提供的分布式锁实现。RLock lock = _this.redissonClient.getLock(key);try {// lock.isLocked():判断锁是否已经被其他线程持有。//lock.isHeldByCurrentThread():判断当前线程是否已经持有该锁。如果当前线程已经持有锁,它不需要重复获取。if (lock.isLocked() && !lock.isHeldByCurrentThread()) {if (lockFail == null) {// 如果 lockFail 为空,则抛出 BizException 异常,表示当前资源忙(例如余额操作正在进行)throw BizException.newInstance(ErrorCode.BUSY);}// 如果锁已经被其他线程持有且不是当前线程持有,且 lockFail 不为空,就执行 lockFail.invoke() 来处理锁获取失败的情况。lockFail.invoke();//lock.tryLock(amount, unit):尝试在指定的时间内(amount 秒)获取锁。如果成功,执行后续的业务操作。}  else if (lock.tryLock(amount, unit)) {try {// 如果锁获取成功,调用 supplier.get() 执行传入的业务逻辑。return supplier.get();} finally {//无论业务逻辑执行成功与否,都要确保释放锁,lock.unlock() 用于释放锁,防止死锁。lock.unlock();}} else {//如果在 tryLock 的超时时间内无法获得锁(即返回 false),就执行 lockFail.invoke(),或者抛出 BizException 异常表示资源繁忙if (lockFail == null) {throw BizException.newInstance(ErrorCode.BUSY);}lockFail.invoke();}//最终返回 null,因为所有锁的操作是围绕着锁获取和释放展开的,所有的业务执行通过 supplier.get() 来完成,返回值由 supplier 提供return null;} catch (InterruptedException e) {//如果线程在等待锁的过程中被中断,则抛出 BizException 异常,表示当前资源忙(此时无法完成操作)。throw BizException.newInstance(ErrorCode.BUSY);}}

这段代码主要实现了一个分布式锁的功能,通过 Redisson 提供的 RLock 来确保在分布式环境下对资源的访问是互斥的,避免多个线程或进程同时访问同一资源(如xxx余额)。

tryLock 方法用于尝试获取锁,并在成功获取锁时执行指定的业务操作(supplier.get())。如果获取锁失败,依据 lockFail 参数的值执行相应的失败处理操作。

锁的获取有超时机制,超过超时时间仍无法获取锁时会触发失败处理

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

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

相关文章

Diving into the STM32 HAL-----DAC笔记

根据所使用的系列和封装&#xff0c;STM32微控制器通常只提供一个具有一个或两个专用输出的DAC&#xff0c;除了STM32F3系列中的少数零件编号实现两个DAC&#xff0c;第一个具有两个输出&#xff0c;另一个只有一个输出。STM32G4 系列的一些较新的 MCU 甚至提供多达 5 个独立的…

【数据分析】认清、明确

1、什么是数据分析。 - 通过对大量的数据进行科学的分析。 - 得出结论&#xff0c;提出建议&#xff0c;辅助公司企业的决策。2、数据分析分为几步。 - 1.明确目的! - 2.收集数据!自己的数据! 自动化采集的数据! - 3.数据处理! - 4.数据分析!数据分析(业务)数据挖掘(代码算法…

Sentinel服务保护

Sentinel是阿里巴巴开源的一款服务保护框架&#xff0c;目前已经加入SpringCloudAlibaba中。官方网站&#xff1a; home | Sentinel Sentinel 的使用可以分为两个部分: 核心库&#xff08;Jar包&#xff09;&#xff1a;不依赖任何框架/库&#xff0c;能够运行于 Java 8 及以…

elasticsearch介绍和部署

1 elasticsearch介绍 Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。可以很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性。Elasticsearch 的实现原理主要分为以下几个步骤&#xff0c;首先用户将数据提交到Elasticsea…

智能安全配电装置在高校实验室中的应用

​ 摘要&#xff1a;高校实验室是科研人员进行科学研究和实验的场所&#xff0c;通常会涉及到大量的仪器设备和电气设备。电气设备的使用不当或者维护不周可能会引发火灾事故。本文将以一起实验室电气火灾事故为例&#xff0c;对事故原因、危害程度以及防范措施进行分析和总结…

大语言模型---Llama模型文件介绍;文件组成

文章目录 1. 概要2. 文件组成 1. 概要 在使用 LLaMA&#xff08;Large Language Model Meta AI&#xff09;权重时&#xff0c;通常会涉及到与模型权重存储和加载相关的文件。这些文件通常是以二进制格式存储的&#xff0c;具有特定的结构来支持高效的模型操作。以下以Llama-7…

12 —— Webpack中向前端注入环境变量

需求&#xff1a;开发模式下打印语句生效&#xff0c;生产模式下打印语句失效 使用Webpack内置的DefinePlugin插件 const webpack require(webpack) module.exports { plugins: [ new webpack.DefinePlugin({ process.env.NODE_ENV:JSON.stringify(process.env.NODE_ENV) }…

【vba源码】导入excel批注信息

Hi&#xff0c;大家好呀&#xff01; 又到了一周一分享的时间&#xff0c;上周繁忙的我都没有给大家直播&#xff0c;视频也没更新&#xff0c;那这周大家放心&#xff0c;都会给大家更新&#xff0c;今天我们来讲点啥呢&#xff1f;每周找优质的内容给大家更新是我最最痛苦的…

Java设计模式 —— Java七大设计原则详解

文章目录 前言一、单一职责原则1、概述2、案例演示 二、接口隔离原则1、概述2、案例演示 三、依赖倒转原则1、概述2、案例演示 四、里氏替换原则1、概述2、案例演示 五、开闭原则1、概述2、案例演示 六、迪米特法则1、概述2、案例演示 七、合成/聚合复用原则1、概述2、组合3、聚…

服务器数据恢复—DS5300存储硬盘指示灯亮黄灯的数据恢复案例

服务器存储数据恢复环境&#xff1a; 某单位一台某品牌型号为DS5300的服务器存储&#xff0c;1个机头4个扩展柜&#xff0c;底层是2组分别由数十块硬盘组建的RAID5阵列。存储系统上层一共分了11个卷。 服务器存储故障&分析&#xff1a; 存储设备上一组raid5阵列上的2块磁盘…

Cloud Native 云原生后端的开发注意事项

在云原生后端开发里&#xff0c;数据管理和存储这块得好好弄。数据库选型得综合考虑&#xff0c;像关系型数据有复杂查询需求就选 MySQL、PostgreSQL&#xff0c;海量非结构化数据就可以考虑 MongoDB、Cassandra 这些。设计数据库得遵循规范化原则&#xff0c;像设计电商订单表…

Mac vscode 激活列编辑模式

列编辑模式在批量处理多行文本时&#xff0c;非常有效&#xff0c;但 vscode 默认情况下&#xff0c;又没有激活&#xff0c;因此记录一下启动方法&#xff1a; 激活列编辑模式 然后就可以使用 Alt&#xff08;Mac 上是 Option 或 Command 键&#xff09; 鼠标左键 滑动选择了…

c#使用高版本8.0步骤

一、找到项目所在怒路&#xff0c;记事本打开.proj文件。 二、记事本打开此文件&#xff0c;<PropertyGroup>后面加入如下语句&#xff1a; <LangVersion>8.0</LangVersion> 关闭并保存。 根据提示全部重新加载即可。

【蓝桥杯C/C++】深入解析I/O高效性能优化:std::ios::sync_with_stdio(false)

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: 蓝桥杯C/C 文章目录 &#x1f4af;前言&#x1f4af;C 语言与 C 语言的输入输出对比1.1 C 语言的输入输出1.2 C 语言的输入输出 &#x1f4af; std::ios::sync_with_stdio(false) 的作用与意义2.1 什么是 std::ios::sync_with_st…

浏览器的事件循环机制

一、请简述浏览器的事件循环机制&#xff08;Event Loop&#xff09;基本原理 浏览器的事件循环机制是用于协调处理 JavaScript 中的异步任务与同步任务执行顺序的一种机制&#xff0c;它确保了代码能够按照合理的顺序执行&#xff0c;避免阻塞页面渲染等情况。其基本原理如下…

GaussDB 华为高斯数据库

GaussDB 是华为推出的一款企业级分布式数据库&#xff0c;旨在为企业提供高效、可靠、安全的数据库服务。GaussDB 基于华为在数据库领域的多年积累&#xff0c;结合人工智能技术和分布式架构&#xff0c;支持多种场景的数据存储与管理需求&#xff0c;是云计算、大数据、人工智…

【Word】一键批量引用论文上标——将正文字体改为上标格式

【Word】一键批量引用论文上标——将正文字体改为上标格式 写在最前面Word一键批量引用论文上标技巧分享核心思路&#xff1a;Word 替换功能 通配符步骤详解1. 打开 Word 替换功能2. 输入通配符模式3. 设置替换格式为上标4. 批量替换 实际效果展示技巧扩展 &#x1f308;你好呀…

SAP 零售方案 CAR 系统的介绍与研究

前言 当今时代&#xff0c;零售业务是充满活力和活力的业务领域之一。每天&#xff0c;由于销售运营和客户行为&#xff0c;它都会生成大量数据。因此&#xff0c;公司迫切需要管理数据并从中检索见解。它将帮助公司朝着正确的方向发展他们的业务。 这就是为什么公司用来处理…

【深度学习之一】2024最新pytorch+cuda+cudnn下载安装搭建开发环境

兵马未动&#xff0c;粮草先行。作为深度学习的初学者&#xff0c;快速搭建一个属于自己的开发环境就是头等大事&#xff0c;可以让我们节省许多的时间。这一期我们主要讲一讲2024年最新pytorchcudacudnn下载安装搭建开发环境&#xff0c;以及安装过程中可能遇到的一些问题以及…

STM32-- 串口介绍

rs485、rs232、rs422 rs485使用&#xff1a; max3485&#xff1a;3.3v左右驱动 max485&#xff1a;5v左右驱动&#xff0c;不过有时候3.3v驱动也可以使用&#xff0c;具体有什么问题或者通过电路规避问题还没有了解过。 rs485和rs422有相同的地方&#xff0c;485满足422的规…