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

设计一个利用事务特性可以阻塞线程的排他锁,并且通过注解和 AOP 来实现

设计思路:
利用数据库表记录锁标识:通过唯一标识符(如方法名 + 参数),我们可以在数据库中插入一条记录,表示当前方法正在执行。这条记录需要记录插入时间。
注解:通过注解标识哪些方法需要加锁,我们可以动态生成唯一标识符。
AOP:使用 AOP 切面处理方法调用逻辑,确保在进入目标方法之前判断是否已经有其他线程持有锁。如果有,则阻塞当前线程,直到锁被释放。
事务:利用事务的隔离性,保证在同一时刻,只有一个线程能够执行某个方法,其他线程需要等待。
超时检测:如果在某个时间点锁没有被释放(例如,锁存在时间超过10分钟),则认为发生了死锁,自动清理相关记录。
步骤及代码实现

  1. 数据库表设计
    首先,我们需要一个数据库表来存储锁的状态。表的结构大致如下:
CREATE TABLE method_lock (id BIGINT AUTO_INCREMENT PRIMARY KEY,lock_key VARCHAR(255) NOT NULL, -- 锁的唯一标识(方法名+参数)created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 锁的创建时间updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 最后更新时间status VARCHAR(50) DEFAULT 'LOCKED', -- 锁的状态,LOCKED 表示锁定,RELEASED 表示释放expired BOOLEAN DEFAULT FALSE -- 是否过期,10分钟未释放的锁算死锁
);
  1. 创建锁的注解
    接下来,我们定义一个注解来标识需要加锁的方法。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodLock {String value(); // 锁的标识(如方法名 + 参数的唯一标识符)
}
  1. 实现 AOP 切面
    在切面中,我们要通过 @Around 来拦截带有 @MethodLock 注解的方法,获取方法的唯一标识,并在数据库中插入或查询锁的状态。
@Aspect
@Component
public class MethodLockAspect {@Autowiredprivate LockRepository lockRepository; // 用于查询和操作数据库的 repository@Around("@annotation(methodLock)") // 拦截带有 @MethodLock 注解的方法public Object around(ProceedingJoinPoint joinPoint, MethodLock methodLock) throws Throwable {String lockKey = methodLock.value() + getMethodSignature(joinPoint); // 生成锁的唯一标识符// 获取当前时间戳long currentTime = System.currentTimeMillis();// 尝试获取锁if (tryAcquireLock(lockKey, currentTime)) {try {// 如果获取到锁,则执行目标方法return joinPoint.proceed();} finally {// 目标方法执行完毕后释放锁releaseLock(lockKey);}} else {// 如果无法获取到锁,则阻塞当前线程或者抛出异常throw new RuntimeException("Unable to acquire lock, try again later.");}}private boolean tryAcquireLock(String lockKey, long currentTime) {// 查询数据库中是否存在该锁记录LockEntity lockEntity = lockRepository.findByLockKey(lockKey);if (lockEntity == null) {// 如果不存在锁记录,则插入新的锁记录LockEntity newLockEntity = new LockEntity();newLockEntity.setLockKey(lockKey);newLockEntity.setCreatedTime(new Timestamp(currentTime));lockRepository.save(newLockEntity);return true;} else {// 如果锁存在,检查锁是否已经过期(超过10分钟)long lockAge = currentTime - lockEntity.getCreatedTime().getTime();if (lockAge > 10 * 60 * 1000) {// 如果锁超时超过10分钟,认为是死锁,清理并重新获取锁lockRepository.deleteByLockKey(lockKey); // 删除死锁记录LockEntity newLockEntity = new LockEntity();newLockEntity.setLockKey(lockKey);newLockEntity.setCreatedTime(new Timestamp(currentTime));lockRepository.save(newLockEntity);return true;}// 如果锁没有过期,则阻塞当前线程return false;}}private void releaseLock(String lockKey) {// 释放锁:删除数据库中的锁记录lockRepository.deleteByLockKey(lockKey);}private String getMethodSignature(ProceedingJoinPoint joinPoint) {// 获取方法签名(例如方法名 + 参数)String methodName = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();StringBuilder signature = new StringBuilder(methodName);for (Object arg : args) {signature.append("-").append(arg != null ? arg.toString() : "null");}return signature.toString();}
}
  1. LockRepository 示例
    假设使用的是 Spring Data JPA 来进行数据库操作,我们可以定义一个简单的 Repository 来操作 method_lock 表。
public interface LockRepository extends JpaRepository<LockEntity, Long> {LockEntity findByLockKey(String lockKey);void deleteByLockKey(String lockKey);
}
  1. LockEntity 实体类
    LockEntity 对应数据库中的 method_lock 表:
@Entity
@Table(name = "method_lock")
public class LockEntity {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String lockKey;@Column(name = "created_time")private Timestamp createdTime;@Column(name = "updated_time")private Timestamp updatedTime;private String status;private Boolean expired;// Getters and Setters
}
  1. 使用示例
    现在,我们可以在需要加锁的方法上使用 @MethodLock 注解,示例如下:
@Service
public class MyService {@MethodLock("uniqueLockKey")@Transactionalpublic void executeTask(String param) {// 执行需要加锁的逻辑System.out.println("Executing task with param: " + param);}
}

关键点总结:
锁的唯一标识:通过方法名和参数生成一个唯一的标识符 lockKey。
数据库表记录锁:通过表记录锁的状态,保证只有一个线程能获取到锁。
AOP 和注解结合:使用 AOP 和注解对方法进行拦截,判断是否已经有其他线程在执行,若没有则获取锁,若有则阻塞或抛出异常。
事务特性:保证同一时刻,只有一个线程能够执行目标方法,其他线程需要等待,。
死锁处理:在锁存在超过 10 分钟时认为是死锁,进行清理。
通过这种方式,可以实现基于事务的排他锁,确保多个线程访问同一资源时进行排队执行

解释:
例如,多个接口调用一个方法,要求多个线程调用该方法时,这些线程排队执行,该方法使用注解,aop切面,通过该注解上的特定字符串和方法名,组成唯一标识,将该标识插入表中,并且记录插入时间,并且该标识是唯一的,当有线程调用该方法时,先组装唯一标识,查询表中是否有该标识的数据,并判断是否时间距离现在是否超过了10分钟,如果超过10分钟就是死锁了,直接删除该标识的所有记录,如果没有查到就插入一条记录,如果该方法没有执行完,就在一个事务里面,该事务没有结束,当有其他方法调用该方法时,就回去查询并插入,由于前一个事务未结束,导致当前唯一标识一致,卡在插入数据时,从而达到阻塞的目的,最后方法结束后将该数据删除。

相关文章:

设计一个利用事务特性可以阻塞线程的排他锁,并且通过注解和 AOP 来实现

设计思路&#xff1a; 利用数据库表记录锁标识&#xff1a;通过唯一标识符&#xff08;如方法名 参数&#xff09;&#xff0c;我们可以在数据库中插入一条记录&#xff0c;表示当前方法正在执行。这条记录需要记录插入时间。 注解&#xff1a;通过注解标识哪些方法需要加锁&a…...

【2024年华为OD机试】 (A卷,100分)- 对称美学(Java JS PythonC/C++)

一、问题描述 题目描述 对称就是最大的美学&#xff0c;现有一道关于对称字符串的美学。已知&#xff1a; 第1个字符串&#xff1a;R第2个字符串&#xff1a;BR第3个字符串&#xff1a;RBBR第4个字符串&#xff1a;BRRBRBBR第5个字符串&#xff1a;RBBRBRRBBRRBRBBR 相信你…...

【教程】数据可视化处理之2024年各省GDP排名预测!

过去的一年里&#xff0c;我国的综合实力显著提升&#xff0c;在新能源汽车、新一代战机、两栖攻击舰、航空航天、芯片电子、装备制造等领域位居全球前列。虽然全国各省市全年的经济数据公布还需要一段时间&#xff0c;但各地的工业发展数据&#xff0c;财政收入数据已大概揭晓…...

Java 将RTF文档转换为Word、PDF、HTML、图片

RTF文档因其跨平台兼容性而广泛使用&#xff0c;但有时在不同的应用场景可能需要特定的文档格式。例如&#xff0c;Word文档适合编辑和协作&#xff0c;PDF文档适合打印和分发&#xff0c;HTML文档适合在线展示&#xff0c;图片格式则适合社交媒体分享。因此我们可能会需要将RT…...

深度学习的原理和应用

一、深度学习的原理 深度学习是机器学习领域的一个重要分支&#xff0c;其原理基于多层神经网络结构和优化算法。以下是深度学习的核心原理&#xff1a; 多层神经网络结构&#xff1a;深度学习模型通常由多层神经元组成&#xff0c;这些神经元通过权重和偏置相互连接。输入数据…...

CAPL语法基础

CAPL语法基础 目录 CAPL语法基础1. 引言2. 数据类型、变量与常量2.1 数据类型2.2 变量2.3 常量2.4 案例1&#xff1a;使用变量和常量计算圆的面积 3. 运算符与表达式3.1 算术运算符3.2 关系运算符3.3 逻辑运算符3.4 位运算符3.5 案例2&#xff1a;使用运算符实现简单的逻辑判断…...

安卓studio生成apk步骤

在写完app之后虽然能在真机上运行 但是在文件夹中找不到相应的apk &#xff0c;注意&#xff01;&#xff01;&#xff01;安卓 studio中可以自动生动生成 apk 下面是生成步骤&#xff1a; 步骤1&#xff1a;build ->make project 步骤2&#xff1a;build ->Generate si…...

Azure主机windows2008就地升级十步

Azure上云主机的windows2008系统需要进行就地升级。 按着微软的升级路径&#xff1a;win2008-->win2012-->win2016-->win2022 第一步&#xff1a;创建快照备份&#xff0c;防止升级失败第二步&#xff1a;升级托管磁盘&#xff0c;在VM管理的地方将磁盘升级成托管磁盘…...

解锁 C# 与 LiteDB 嵌入式 NoSQL 数据库

一、开篇&#xff1a;邂逅 C# 与 LiteDB 新世界 在当今的软件开发领域&#xff0c;数据管理如同建筑的基石&#xff0c;而选择一款合适的数据库则是项目成功与否的关键因素之一。对于 C# 开发者来说&#xff0c;面对琳琅满目的数据库选项&#xff0c;如何抉择常常令人头疼。今…...

7 分布式定时任务调度框架

先简单介绍下分布式定时任务调度框架的使用场景和功能和架构&#xff0c;然后再介绍世面上常见的产品 我们在大型的复杂的系统下&#xff0c;会有大量的跑批&#xff0c;定时任务的功能&#xff0c;如果在独立的子项目中单独去处理这些任务&#xff0c;随着业务的复杂度的提高…...

七星棋类游戏源码:两百玩法开源修复

这套七星棋类源码&#xff0c;覆盖六大省区&#xff08;湖南双端、湖北、山西、江苏、贵州等&#xff09;&#xff0c;安卓与苹果端都能轻松适配&#xff0c;汇集 6 个端口与 200 多种子游戏玩法。此版本为二次开发修复版&#xff0c;功能完备且源码完全公开&#xff0c;包括乐…...

未来世界:科技引领的奇幻篇章

科技发展的这么快&#xff0c;未来的世界将会是什么样的呢&#xff1f; 在人类历史的长河中&#xff0c;科技始终是推动社会进步的核心力量。从古老的四大发明到如今的人工智能、基因编辑、量子计算等前沿技术&#xff0c;科技发展的速度日新月异。我们不禁会想&#xff0c;在…...

[python3]Uvicorn库

Uvicorn 是一个用于运行 ASGI&#xff08;Asynchronous Server Gateway Interface&#xff09;应用程序的轻量级服务器。ASGI 是 Python Web 应用程序接口的一种扩展&#xff0c;它不仅支持传统的同步 Web 请求处理&#xff0c;还支持异步请求处理、WebSockets 以及 HTTP/2。 h…...

istio-proxy oom问题排查步骤

1. 查看cluster数量 cluster数量太多会导致istio-proxy占用比较大的内存&#xff0c;此时需检查是否dr资源的host设置有配置为* 2. 查看链路数据采样率 若采样率设置过高&#xff0c;在压测时需要很大的内存来维护链路数据。可以调低采样率或增大istio-proxy内存。 检查iop中…...

Flutter:使用FVM安装多个Flutter SDK 版本和使用教程

一、FVM简介 FVM全称&#xff1a;Flutter Version Management FVM通过引用每个项目使用的Flutter SDK版本来帮助实现一致的应用程序构建。它还允许您安装多个Flutter版本&#xff0c;以快速验证和测试您的应用程序即将发布的Flutter版本&#xff0c;而无需每次等待Flutter安装。…...

关于物联网的基础知识(二)——物联网体系结构分层

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于物联网的基础知识&#xff08;二&a…...

[程序设计]—代理模式

[程序设计]—代理模式&#x1f473; 本文章记录学习于——52.面向切面&#xff1a;AOP-场景模拟_哔哩哔哩_bilibili 最近闲来无事&#xff0c;在学习Spring的源码&#xff1a; 后面慢慢更新源码系列blog&#xff0c;希望多多关注&#x1f64f;&#x1f64f; 目前已经总结的b…...

26、【OS】【Nuttx】用cmake构建工程

背景 之前wiki 14、【OS】【Nuttx】Nsh中运行第一个程序 都是用 make 构建&#xff0c;准备切换 cmake 进行构建&#xff0c;方便后续扩展开发 Nuttx cmake 适配 nuttx项目路径下输入 make distclean&#xff0c;清除之前工程配置 adminpcadminpc:~/nuttx_pdt/nuttx$ make …...

C#中序列化的选择:JSON、XML、二进制与Protobuf详解

C#中序列化的选择&#xff1a;JSON、XML、二进制与Protobuf详解 在C#开发中&#xff0c;序列化是将对象转换为可存储或传输的格式的过程&#xff0c;而反序列化则是将存储或传输的数据重新转换为对象的过程。选择合适的序列化方式对应用程序的性能、可维护性和兼容性至关重要。…...

单片机实现模式转换

[任务] 要求通过单片机实现以下功能&#xff1a; 1.单片机有三种工作模式(定义全局变量MM表示模式&#xff0c;MM1&#xff0c;2&#xff0c;3表示三种不同的模式) LED控制模式 风扇控制模式 蜂鸣器控制模式 2.可以在某一个模式下通过拓展板KEY1按键控制设备 (按…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...