记录一次因执行时间过长锁已经释放导致finally块再次unlock引发的异常

news2025/7/9 8:42:56

一、前言

因为我的一个需求需要请求一个耗时比较长的接口(耗时长其实是对接方的锅),该接口交给了Spring事务管理,并且使用了分布式锁,但是在请求的时候,出现error,看日志发现是unlock的时候没有锁可以去解锁,才爆出的异常。然后又由于使用了事务,导致整个请求的数据被回滚。
在这里插入图片描述
然后就通过日志看请求时间和这次异常的时间,发现整整相差了1分钟,而分布式锁设置的时间只有5s

    @Override
	@PostMapping(path = "xxxxx")
	@Transactional(rollbackFor = Exception.class)
	public Result create(@RequestBody Request request) {
	// 通过缓存防止重复申请
		String lockDate = new StringBuilder().append(request.getId()).toString();
		DistributedLock lock = distributedLockService.getLock(LOCK_PREFIX + lockDate);
		if (!lock.tryLock(0, 5, TimeUnit.SECONDS)) {
			return Result.error(100, "请勿重复请求");
		}
		try{
		    //业务代码
		}catch (Exception e) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			logger.warn(e.getMessage());
			return Result.error(100, "证书申请失败");
		} finally {
		     lock.unlock();
		}

二、解决

这就导致tryLock设置的时间已经超过,锁此时已自动释放,那么走到finally块时,又执行lock.unlock(),导致上述异常,而数据又回滚,就会产生好像执行了但实际上啥也没有的情景。
那么我们的解决思路有两种:

  • 第一种延长锁的持续时间,但是这个我之前说过这个超时是因为对接方的锅,如果使用其他对接方请求这个接口还是很快的。那么这个想法就先pass
  • 那第二种解决办法也是最后采取的解决方式,我们知道其实这个bug引起的最不好的体验就是整个请求产生的数据因为发生Bug,被Spring事务回滚了,导致我们想知道发生了啥,去db中找也找不到,而且更为重要的是,如果采用上一种延长锁的持续时间,可能会导致锁的竞争更加激烈,会影响系统的性能,并且其实大部分请求并不需要那么久,只是个别请求产生的延迟导致的Bug.那么最终采取的解决方式也比较简单:就是在finally块处,对lock.unlock进行try/catch捕获,如果捕获到异常,什么也不处理,这样就算有时候出现超时,超过了锁的持续时间,就算锁已被释放,这个时候去执行finally块被捕获,也不会被Spring事务回滚
@Override
	@PostMapping(path = "xxxxx")
	@Transactional(rollbackFor = Exception.class)
	public Result create(@RequestBody Request request) {
	// 通过缓存防止重复申请
		String lockDate = new StringBuilder().append(request.getId()).toString();
		DistributedLock lock = distributedLockService.getLock(LOCK_PREFIX + lockDate);
		if (!lock.tryLock(0, 5, TimeUnit.SECONDS)) {
			return Result.error(100, "请勿重复请求");
		}
		try{
		    //业务代码
		}catch (Exception e) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			logger.warn(e.getMessage());
			return Result.error(100, "证书申请失败");
		} finally {
		   try{
		     lock.unlock();
		     }catch(Exception e){
		     }
		}

当然,唯一不好的,就是如果你的公司如果使用了sonarLint,会爆

Unlock this lock along all executions paths of this method

但是这个并不会产生什么大问题,不去管它就好,如果大家有什么更好的解决方案,可以评论区一起讨论。

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

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

相关文章

牛客网语法篇练习复合类型(二)

1.输入NxM矩阵,矩阵元素均为整数,计算其中大于零的元素之和。 a,b map(int,input().split()) list1 [] sum 0 for i in range(a):list1.extend(list(map(int,input().split()))) for i in list1:if i>0:sumi print(sum) 2.给你一个整数n&#xff…

辨别代码能否引发线程安全问题--避免在平时写代码时引发线程安全问题

前景提要: 本篇文章只是入门,目的在于在脑海中构建一个Java运行的模型,然后可以在平时写代码时对是否引发线程安全问题有感知。 文章目录引入了解辨别线程安全问题之前先来构建一个计算机运行模型了解线程安全问题怎么能不知道线程和进程了解…

搭建repo服务器管理多个git工程

参考自:搭建repo服务器管理多个git工程     repo系列讲解 —— Android系统源码(AOSP)下载 1、repo介绍 Android使用git作为代码管理工具,开发了gerrit进行代码审核,以便更好的对代码进行集中式管理。还开发了repo命令行工具&#xff0…

MySQL8.0 binlog进阶

MySQL8.0经过这几年的操揉磨治,已经上升到海平面了。其中binlog也悄然无声带来了不一样的变化。高可用核心复制基础binlog变化更应该进一步了解。从参数入手,了解带来的变化。 slave回放算法 slave_rows_search_algorithms 当使用基于 row-based复制格…

牛客网语法篇练习循环控制(二)

1.今天牛牛学到了回文串,他想在数字里面找回文,即回文数,回文数是正着读与倒着读都一样的数,比如1221,343是回文数,433不是回文数。请输出不超过n的回文数。 a int(input()) for i in range(1,a1):n str…

CSS-counter 计数器详细教程+使用场景示例

counter一. counter计数器二. 属性和方法1. 计数器命名/重置2. 计数器-值递增规则3. 计数器显示 counter() / counters() 函数三 代码示例1. 重新开始计数2. counters嵌套使用3. 借助CSS计数器呈现CSS var变量值一. counter计数器 计数器是一种特殊的数字跟踪器,通常…

systemd的unit配置文件详解

Systemd 是 Linux 的系统和服务的管理器,兼容 SysV 和 LSB初始化脚本,Systemd有以下特性: 积极的并行化能力使用套接字和 D-Bus 激活来启动服务提供按需启动守护进程,使用 Linux cgroups 跟踪进程支持系统状态的快照和恢复维护挂…

艾美捷Cas9核酸酶应用说明及实例展示

Product Description:Recombinant Streptococcus pyogenes Cas9 (wt) protein expressed in an E. coli . Form:Liquid Preparation Method:E. coli expression system Purity:≥ 95% by SDS-PAGE Activity:20 nM CRISPR/Cas9-C-NLS nuclease incubated for 1 hour at 37℃…

【新知实验室 TRTCIM】实时互动课堂最佳实践

【新知实验室 TRTC&IM】实时互动课堂最佳实践一、新知实验室-TRTC腾讯云音视频产品体验官计划活动简介二、产品简介TRTCIM三、最佳实践3.1 官方快速上手TRTC(快速跑通)3.1.1 注册腾讯云账号3.1.2 使用实时音视频(需先开通)3.1.3 创建应用3.1.4 查看项目(查看密钥和快速上手…

java基础—String

我们都知道 创建一个字符串最简单的方式是 String meaasge "java资讯";当然还可以用构造来创建 (不推荐,开发中不要用) String str2new String("java资讯");这两种创建最主要的区别在于,一个在公共池中&…

gitlab CI/CD 自动化部署vue项目到阿里云服务器步骤

目录1,gitlab托管vue项目2,本地项目连接到远程仓库3,设置gitlab-runner4,编写yml文件5,部署到阿里云服务器(本地设置)5.1 安装相关依赖5.2 vue项目中添加deploy.js文件5.3 注册deploy命令5.4 验…

文本生成图像工作简述2--常用数据集分析与汇总

文本到图像的 AI 模型仅根据简单的文字输入就可以生成图像。用户可以输入他们喜欢的任何文字提示——比如,“一只可爱的柯基犬住在一个用寿司做的房子里”——然后,人工智能就像施了魔法一样,会产生相应的图像。 文本生成图像(te…

实验2:Arduino的nRF24L01双向收发实验

实验结果: 00节点向01发送:00ReqMesFor01 01节点向00发送:CodeNewNiceBoy 并且在串口打印出相应信息 硬件电路: 01 软件 00节点代码: /*00 */#include <SPI.h> #include <nRF24L01.h> #include <RF24.h> RF24 radio(9, 10);// CE, CSNconst char te…

dolphinscheduler 2.0.5 性能手动测试

目录&#x1f42c;官方配置文件说明&#x1f42c;测试并发量&#x1f420;线程数量设置100&#x1f420;线程数量设置200&#x1f420;线程数量设置500&#x1f42c;测试结论&#x1f42c;官方配置文件说明 官方说明 master.exec.threads&#xff1a; master工作线程数量,用于…

智能晾衣架(二)--功能实现

本文素材来源于红河学院 工学院 作者&#xff1a;赵德森 张艺锦 潘志慧 曹紫康 指导老师&#xff1a;江洁 张龙超 1. 自动升降功能 我们设计时采用了热释电传感器&#xff08;人体红外传感器&#xff09;&#xff0c;在热释电传感器感应到有人靠近时&#xff0c;晾衣架通…

C++:内存管理:C++内存管理详解(二):带你攻破内存管理

前言&#xff1a; 任何程序运行起来都需要分配内存空间存放该进程的资源信息&#xff0c;C程序也不例外。C程序中的变量、常量、函数、代码等等信息所存放的区域都有所不同&#xff0c;不同的区域又有不同的特性。 欺骗C进程 每一个C语言的程序被执行起来的时候系统为了方便开…

字符串的简单介绍和字符串的大小比较

以前就写过一篇关于String的文章&#xff0c;今天再来写一篇&#xff0c;更加深入了解一下String类 &#x1f550;1.String类的定义 &#x1f551;2.String类的创建 &#x1f552;3.字符串的大小比较 1.之前在C语言中我们已经学到了字符类型&#xff0c;但是C语言没有Strin…

Oracle-Rman duplicate文件坏块问题处理ORA-19849 19612

前言: 最近&#xff0c;在使用rman duplicate进行备库环境搭建时&#xff0c;遇到了ORA-19849 19612坏块报错&#xff0c;最终分析是发现由于网络的配置导致。 问题: 在 ORACLE 12.2.0.1.180417 通过RMAN duplicate进行备库初始化&#xff0c;在复制文件的过程中&#xff0c;…

FTP服务器移植到Linux开发板

FTP服务器移植到Linux开发板 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录FTP服务器移植到Linux开发板前言一、vsftpd源码下载二、vsftpd移植及配置1.vsftpd移植2.vsftpd配置2.1 配置vsftpd.conf2.2 添加新用户2…

LVS+Keepalived群集

目录 一.keeepalived工具介绍 1.1 专为LVS和HA设计的一款健康检查工具 1.2 Keepalived实现原理剖析 1.3 VRRP工作过程 1.4 Keepalived&#xff0c;VRRP及其工作原理 1.5 Keepalived体系主要模块及其作用 二、LVSKeepalived 高可用群集的搭建步骤 1、配置负载调度器&…