当前位置: 首页 > news >正文

分布式锁(防止同时操作同一条数据)实现分析

1. deleteLocked 方法:

public R deleteLocked(String id, String username) {String examReportUserKey = "examReportId_" + id + "_" + username;stringRedisTemplate.delete(examReportUserKey);return R.ok();
}

功能:删除指定用户对某个 ExamReport 的锁。
实现:通过删除 Redis 中对应的键来释放锁。

2. checkIfLocked 方法:

public boolean checkIfLocked(Long id, String username) {String examReportKey = "examReportId_" + id + "_";String examReportUserKey = "examReportId_" + id + "_" + username;Set keys = stringRedisTemplate.keys(examReportKey + "*");boolean iflocked = true;if (keys == null || keys.size() == 0) {iflocked = false;}for (Object key : keys) {if (examReportUserKey.equals(key.toString())) {String lockflag = stringRedisTemplate.opsForValue().get(examReportUserKey).toString();if (lockflag.equals("1")) {iflocked = false;break;}}}return iflocked;
}
  • 功能:检查某个 ExamReport 是否被其他用户锁定。
  • 实现:
    获取所有以 examReportKey 开头的键。
    检查是否存在与当前用户相关的键,并且该键的值为 "1"。
    如果存在且值为 "1",则表示未被锁定;否则表示已被锁定。

3. getLockIds 方法:

public String getLockIds(String username) {String examReportKey = "examReportId_";Set keys = stringRedisTemplate.keys(examReportKey + "*");String lockIds = "";List<String> lockIdsList = new ArrayList<>();for (Object key : keys) {String ids = key.toString();String[] parts = ids.split("_");if (!parts[2].equals(username)) {if (!lockIdsList.contains(parts[1])) {lockIdsList.add(parts[1]);}}}lockIds = String.join(",", lockIdsList);return lockIds;
}
  • 功能:获取与特定用户名不匹配的锁 ID 列表。
  • 实现:
    获取所有以 examReportKey 开头的键。
    提取与特定用户名不匹配的锁 ID,并去重。

4. checkUserLocked 方法

public void checkUserLocked(Long id, String username) {String examReportUserKey = "examReportId_" + id + "_" + username;stringRedisTemplate.opsForValue().set(examReportUserKey, "1", 1, TimeUnit.HOURS);
}
  • 功能:为指定用户对某个 ExamReport 设置锁。
  • 实现:
    在 Redis 中设置一个键,键名为 examReportUserKey,值为 "1",过期时间为 1 小时。

5. examReportService.lambdaQuery 方法

ExamReport examReport = examReportService.lambdaQuery().eq(ExamReport::getDelFlag, "0").eq(ExamReport::getStatus, 1).eq(ExamReport::getId, id).notIn(StringUtils.hasLength(ids), ExamReport::getId, ids).last("limit 1").one();
  • 功能:查询符合条件的 ExamReport 记录,并排除已经获取到的锁 ID。
  • 实现:
    eq(ExamReport::getDelFlag, "0"):查询 del_flag 为 "0" 的记录。
    eq(ExamReport::getStatus, 1):查询 status 为 1 的记录。
    eq(ExamReport::getId, id):查询 id 为指定 id 的记录。
    notIn(StringUtils.hasLength(ids), ExamReport::getId, ids):如果 ids 不为空,则排除 id 在 ids 列表中的记录。
    last("limit 1"):在查询的最后添加 LIMIT 1,确保只返回一条记录。
    one():执行查询并返回一条记录。

6. queryVerifyList 方法

public R queryVerifyList(@Param("prevId") String prevId) {String username = SecurityUtils.getUser().getUsername();String ids = getLockIds(username);RestTemplate restTemplate = new RestTemplate();Map<String, Object> map = new HashMap<>();map.put("ids", ids);map.put("prevId", prevId);String url = basePath + "/appapi/queryVList?ids={ids}&prevId={prevId}";R result = restTemplate.getForObject(url, R.class, map);if (result == null) {return R.failed("请求失败");}if (result.getCode() == 200) {ExamReportCheckVO examReportCheckVO = JSON.parseObject(JSON.toJSONString(result.getData()), ExamReportCheckVO.class);checkUserLocked(examReportCheckVO.getId(), username);deleteLocked(prevId, username);return R.ok(examReportCheckVO);}return result;
}
  • 功能:查询验证列表,并处理锁的获取和释放。
  • 实现:
    获取当前用户的用户名。
    调用 getLockIds 方法获取当前用户未锁定的 ExamReport ID 列表。
    使用 RestTemplate 发送 HTTP GET 请求到指定 URL,传递 ids 和 prevId 参数。
    处理请求结果:
    如果请求失败,返回失败响应。
    如果请求成功且状态码为 200,解析返回的数据为 ExamReportCheckVO 对象。
    调用 checkUserLocked 方法为新的 ExamReport 设置锁。
    调用 deleteLocked 方法释放旧的 ExamReport 锁。
    返回成功响应,包含 ExamReportCheckVO 对象。
    如果请求成功但状态码不是 200,直接返回请求结果。

分布式锁的实现原理
1. 锁的获取
checkUserLocked 方法:
为指定用户对某个 ExamReport 设置锁。
键的格式为 examReportId_{id}_{username},值为 "1",过期时间为 1 小时。
2. 锁的检查
checkIfLocked 方法:
检查某个 ExamReport 是否被其他用户锁定。
通过查询 Redis 中的键来判断是否存在与当前用户相关的锁,并且该锁的值为 "1"。
如果存在且值为 "1",则表示未被锁定;否则表示已被锁定。
3. 锁的释放
deleteLocked 方法:
删除指定用户对某个 ExamReport 的锁。
通过删除 Redis 中对应的键来释放锁。
4. 查询记录
examReportService.lambdaQuery 方法:
查询符合条件的 ExamReport 记录,并排除已经获取到的锁 ID。
确保返回的记录是未被锁定的。
5. 查询验证列表
queryVerifyList 方法:
获取当前用户的用户名。
获取当前用户未锁定的 ExamReport ID 列表。
发送 HTTP 请求查询验证列表。
处理请求结果,设置新锁并释放旧锁。
优缺点
优点
简单易懂:实现逻辑简单,容易理解和维护。
高可用性:利用 Redis 的高可用性和持久化特性,确保锁的可靠性和一致性。
自动过期:设置锁的过期时间,避免死锁问题。
缺点
性能问题:频繁的 keys 操作可能会导致性能瓶颈,特别是在数据量较大的情况下。
竞态条件:在高并发环境下,可能存在竞态条件,导致锁的不一致。
依赖 Redis:整个锁机制依赖于 Redis,如果 Redis 出现故障,锁机制将失效。
示例
假设 Redis 中有以下键:
examReportId_123_user1
examReportId_456_user1
examReportId_789_user2
examReportId_101_user3
操作流程
获取锁 ID 列表:
调用 getLockIds("user1") 会返回 789,101。
查询记录:
使用 examReportService.lambdaQuery 方法查询符合条件的 ExamReport 记录,并排除 789 和 101 这些已经被锁定的 ID。
检查锁状态:
调用 checkIfLocked(123, "user1") 会返回 false,表示 123 已经被 user1 锁定。
释放锁:
调用 deleteLocked("123", "user1") 会删除 examReportId_123_user1 键,释放锁。
查询验证列表:
调用 queryVerifyList("123") 会发送 HTTP 请求查询验证列表,并处理锁的获取和释放。
总结
通过上述方法,实现了一个基于 Redis 的分布式锁机制,确保在同一时间只有一个用户可以访问某个资源,从而避免并发冲突。虽然存在一些性能和竞态条件的问题,但在大多数场景下,这种实现方式是有效且可靠的。

相关文章:

分布式锁(防止同时操作同一条数据)实现分析

1. deleteLocked 方法&#xff1a; public R deleteLocked(String id, String username) {String examReportUserKey "examReportId_" id "_" username;stringRedisTemplate.delete(examReportUserKey);return R.ok(); } 功能&#xff1a;删除指定用户…...

【已解决,含泪总结】Ubuntu18.04下非root用户Anaconda3卸载重装,conda install终于不再报错

为什么要卸载重装 因为我最初安装的Anaconda3的版本是5.2.0&#xff0c;适合python3.6.5&#xff0c;其下的conda版本是4.5.4 我一开始本着能用则用&#xff0c;毕竟不是很懂的原则&#xff0c;尽量不要卸掉重来 但。。。bug像滚雪球一样&#xff0c;越来越多 conda install指…...

大语言模型(LLM)量化基础知识(一)

请大家关注我的知乎博客&#xff1a;- 派神 - - 知乎 随着大型语言模型 (LLM) 的参数数量的增长,与其支持硬件&#xff08;加速器内存&#xff09;增长速度之间的差距越来越大&#xff0c;如下图所示&#xff1a; 上图显示&#xff0c;从 2017 年到 2022 年&#xff0c;语言模…...

hadoop面试题

一、单项选择题 1、目前&#xff0c;Hadoop的最高版本是哪个&#xff08; A &#xff09; A、Hadoop3.x B、Hadoop2.x C、Hadoop4.x D、Hadoop1.x 2、大数据的4V特征是指? &#xff08; B &#xff09; A、数据量大(Volume)、类型繁多(Variety)、价值密度低(Va…...

mysql 安装 windows

新版安装 新版本安装 如果出现initializing database无法安装 则用我当前版本传送门 如MySQL 安装时没有developer default 选项 解决方法传送门 如果上述还不行 可以选择full 汉化下载 传送门...

24下软考中级网络工程师考前必背22页

数据中心选址原则 1、地理位置&#xff1a;备选址地点发生自然灾害的概率和频率、环境危害因素以及气候因素 2、电力能源供应&#xff1a;可用性、成本因素 3、通讯基础设施&#xff1a;光纤主干线路及其距数据中心选址的距离、光纤类型、服务运营商的类型及其支持的服务模式…...

Java类和对象(下篇)

今天接着学习类和对象(苦笑)(苦笑)(苦笑) 1. 封装 1.1 封装的概念 面向对象程序三大特性&#xff1a;封装、继承、多态。 而类和对象阶段&#xff0c;主要研究的就是封装特性。 何为封装呢&#xff1f;简单来说就是套壳屏蔽细节。 举例&#xff1a;对于计算机使用者而言&am…...

k8s图形化显示(KRM)

在master节点 kubectl get po -n kube-system 这个命令会列出 kube-system 命名空间中的所有 Pod 的状态和相关信息&#xff0c;比如名称、状态、重启次数等。 systemctl status kubelet #查看kubelet状态 yum install git #下载git命令 git clone https://gitee.com/duk…...

apache poi 实现下拉框联动校验

apache poi 提供了 DataValidation​ 接口 让我们可以轻松实现 Excel 下拉框数据局校验。但是下拉框联动校验是无法直接通过 DataValidation ​实现&#xff0c;所以我们可以通过其他方式间接实现。 ‍ 步骤如下&#xff1a; 创建一个隐藏 sheet private static void create…...

【canal 中间件】canal 实时监听 binlog

文章目录 一、安装 MySQL1.1 启动 mysql 服务器1.2 开启 Binlog 写入功能1.2.1创建 binlog 配置文件1.2.2 修改配置文件权限1.2.3 挂载配置文件1.2.4 检测 binlog 配置是否成功 1.3 创建账户并授权 二、安装 canal2.1 安装 canal-admin(可选)2.1.1 启动 canal-admin 容器2.1.2 …...

JVM垃圾收集算法、对应收集器和选择建议

如果说垃圾收集算法是内存回收的方法论&#xff0c;那么垃圾收集器就是内存回收的具体实现。 到目前为止还没有最好的垃圾收集器出现&#xff0c;也没万能的垃圾收集器。实际使用中&#xff0c;根据具体应用场景选择合适的垃圾收集器。 1、垃圾收集算法 垃圾收集算法可以从高…...

如何在算家云搭建Aatrox-Bert-VITS2(音频生成)

一、模型介绍 ‌ Aatrox - Bert -VITS2 模型是一种基于深度学习的语音合成系统&#xff0c;结合了 BERT 的预训练能力和 VITS2 的微调技术&#xff0c;旨在实现高质量的个性化语音合成。 二、模型搭建流程 1. 创建容器实例 进入算家云的“应用社区”&#xff0c;点击搜索找到…...

ceph灾备之cephfs snapshot mirror和rsync对比

背景 最近要做ceph集群之间的灾备功能&#xff0c;主要讨论文件存储&#xff0c;因为ceph集群容量越来越大&#xff0c;接入的业务也越来越多&#xff0c;一旦出现故障&#xff0c;恢复时间都是小时级(根据经验每年都会出现几次这种事故)&#xff0c;对于核心业务无法接受&…...

【工具分享】Plutocrypt勒索病毒解密工具

前言 Plutocrypt勒索软件首次出现在2021年&#xff0c;作为CryptoJoker勒索软件的变种。该恶意软件通过钓鱼邮件和恶意链接传播&#xff0c;主要针对个人和小型企业用户。Plutocrypt使用了.NET框架开发&#xff0c;并依赖AES-256和RSA-4096的加密算法来加密受害者的文件。与Cr…...

IDEA启动提示Downloading pre-built shared indexes

Download pre-built shared indexes Reduce the indexing time and CPU load with pre-built JDK shared indexes 翻译&#xff1a; 下载预构建的共享索引 使用预构建的JDK共享索引减少索引时间和CPU负载. 使用预构建的JDK共享索引可以显著减少索引构建时间和CPU负载&#xf…...

[HCTF 2018]WarmUp 1--详细解析

打开靶机&#xff0c;进入界面&#xff1a; 信息搜集 当前界面没有任何有用信息。 想到查看页面源代码。右键–查看页面源代码 看到hint&#xff1a;<!--source.php--> 进入/source.php页面&#xff0c;看到页面源代码&#xff1a; <?phphighlight_file(__FILE_…...

软考教材重点内容 信息安全工程师 第1章 网络信息安全概述

第 1 章 网络信息安全概述 1.1.1 网络信息安全相关概念 狭义上的网络信息安全特指网络信息系统的各组成要素符合安全属性的要求&#xff0c;即机密性、完整性、可用性、抗抵赖性、可控性。 广义上的网络信息安全是涉及国家安全、城市安全、经济安全、社会安全、生产安全、人身安…...

TOSHIBA 74VHC00FT COMS汽车、工业企业的选择

74VHC00FT 是一种四路双输入 NAND 门&#xff0c;属于 CMOS 系列数字集成电路。它采用东芝先进的硅栅 C2MOS 技术设计&#xff0c;能够实现类似于双极性肖特基 TTL 逻辑电路的高速运行&#xff0c;同时保持 CMOS 器件的低功耗。这种独特的结合使其非常适合需要高性能和低功耗的…...

【Android】使用productFlavors构建多个变体

项目需求 在一个设备上安装两个一样的程序app 需求解决 我们知道每一个app都有一个包名的&#xff0c;如果一个app在Android设备上安装之后&#xff0c;再安装这个app的话会进行覆盖安装&#xff0c;因为他们两个的包名是一样的&#xff0c;默认是一个app。 但是我们现在需…...

ubuntu 22.04 防火墙 ufw

Ubuntu&#xff08;22.04&#xff09;云主机SSH安全加固 https://blog.csdn.net/qq_44846097/article/details/141098092 ubuntu22.04防火墙策略 https://blog.csdn.net/sunyuhua_keyboard/article/details/139493464 Ubuntu 22.04 防火墙设置和开放端口命令 https://blog.c…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…...