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

异步导入中使用SecurityUtils.getSubject().getPrincipal()获取LoginUser对象导致的缓存删除失败问题

结论

SecurityUtils.getSubject().getPrincipal()实际用的也是ThreadLocal,而ThreadLocal和线程绑定,异步会导致存数据丢失,注意!

业务背景

最近,系统偶尔会出现excel导入成功,但系统却提示存在进行中的导入的问题(并且等待了较长的时间还是不行)。这边跟进排查一下。

实现现状

导入的时候,会对参数进行校验,其中就有数据重复校验。
看了一下,前辈是用redis的set来进行的去重校验操作。用LoginUser获取用户id,固定前置+用户id拼接作为redis的key,需要去重的字段拼接成map作为值。主业务方法结束的时候用传入的LoginUser的用户id去拼接key来删除key(因为校验方法是框架带的,所以无法传参将LoginUser传进去)。
判断是否存在正在进行的导入是直接拼接key来查redis,key存在则说明有正在进行中的导入。

 private boolean hashCacheExcelVerifyDataGroupVerify(SdSchoolQuestionBankTestPaperVerify verify, String prefix) {LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();boolean groupVerifySuccess = true;if (verify == null) {return groupVerifySuccess;}try {//校验成功,成功返回true、失败返回falseString userId = loginUser.getId();String key = prefix + userId;Map<String, Object> map = new HashMap<>();map.put("xxxNo", verify.getTestPaperName().trim() + verify.getXxxNo().trim());//有效期设置为30分钟long expireTime = 30 * 60;SetOperations setOperations = redisTemplate.opsForSet();setOperations.getOperations().expire(key, expireTime, TimeUnit.SECONDS);Set members = setOperations.members(key);if (!members.contains(map)) {//如果不存在,将数据缓存到redis中,并设置有效期为30分钟,当执行完导入操作之后删除缓存setOperations.add(key, map);} else {groupVerifySuccess = false;}} catch (Exception e) {log.error("去重校验失败", e);}return groupVerifySuccess;}

上面的方案总体来说是可以实现的,只不过具体实现的时候出现了一些小毛病。
一眼看过去,先设置过期时间,再设置值,这不是虚空设过期时间(如果导入一条数据,直接永不过期)。不过一般导入的数量也不是一条,按理说过半个小时应该能用才对。不过还是改了再说,把设置过期时间的代码放到setOperations.add(key, map)下面。
接着查,发现执行完业务代码之后,只有成功才会删除key,原来问题出在这。于是给异常后面加上一个finally,在finally里面删除key,这下,无论你啥时候过期,删除了就屁事没有。
测试环境验证一下。非常好,没问题,提测,问题解决,简简单单。

一波又起

到第二天,业务反馈,又出现一直处于导入中的情况。并且该账号半个小时以内并没有用过该excel导入。

奇怪了,仔细又查了一遍代码,不应该呀,在finally里面有删除。无论如何肯定会执行删除操作呀。然后去看被限制人的导入,半个小时内并没有导入。
上redis一看,还真有缓存,卧槽,见鬼了。再去看半个小时内是否有导入,还真有,再细看过期时间和导入时间,居然还对的上。
emm,有情况。突然想到LoginUser的获取和ThreadLocal有点像,会不会是异步导致的问题。于是本地启动去测,用工具跑了很多次(只用了一个账号)。异步前后获取到的用户都是同一个,于是认为LoginUser比ThreadLocal牛逼,在异步的时候还会去提前更改盒子里的内容。(其实是因为只有一个用户,用来用去都只有一个用户,各个线程里面存的都是该用户,当然获取到的是一致的)

灵光一闪

到第二天,突然想到,A导入,却导致B被限制。那应该要多用户去测才对。于是更改测试方式,结果获取到的结果显示,异步前后获取到的LoginUser不一致。卧槽!!!难崩,原来是这个原因,原来我猜想是对的。
因为新实现的导入都是直接用一个key作为判断是否存在正常导入的依据,并且异步之后删除key用的也是通过传参传入的LoginUser,而校验用的是ThreaLocal,自然不会出现这种问题。

解决方案

那看来得改校验重复的实现方案了,用我最喜欢的ThreadLocal。创建一个ThreadLocal静态变量,这样里面存的数据都和线程相关,异步之后一直是同一个线程,自然不会出现错误的情况,最后在finally里面清空ThreadLocal,完美。
后续,果然没有再出现过错误限制导入的情况。

原因分析

因为异步用到了线程池。请求进来的时候,会校验用户信息,并将用户信息存入LoginUser中,以供全局使用。在线程执行结束之后,线程回到线程池,但线程对应的ThreadLocal的数据却没有清空。一般情况下,如果都是走Controller进来的请求都不会有问题,因为每次请求进来都会将新的用户信息set进去。但当异步的时候,就没有set用户信息的过程,线程内的用户信息还是上一次进入Controller用该线程的用户的用户信息。也就存在数据对不上的情况。而在异步中直接使用SecurityUtils.getSubject().getPrincipal()也就是犯了上面的错。

总的来说,就是SecurityUtils.getSubject().getPrincipal()实际用的也是ThreadLocal,而ThreadLocal和线程绑定,异步会导致数据丢失,注意!

相关文章:

异步导入中使用SecurityUtils.getSubject().getPrincipal()获取LoginUser对象导致的缓存删除失败问题

结论 SecurityUtils.getSubject().getPrincipal()实际用的也是ThreadLocal&#xff0c;而ThreadLocal和线程绑定&#xff0c;异步会导致存数据丢失&#xff0c;注意&#xff01; 业务背景 最近&#xff0c;系统偶尔会出现excel导入成功&#xff0c;但系统却提示存在进行中的…...

大数据机器学习深度解读决策树算法:技术全解与案例实战

大数据机器学习深度解读决策树算法&#xff1a;技术全解与案例实战 本文深入探讨了机器学习中的决策树算法&#xff0c;从基础概念到高级研究进展&#xff0c;再到实战案例应用&#xff0c;全面解析了决策树的理论及其在现实世界问题中的实际效能。通过技术细节和案例实践&…...

【开源Mongdb驱动】SpringBoot+Mybatis+Mongdb融合使用教程

#【开源Mongdb驱动】SpringBootMybatisMongdb无缝融合使用教程 介绍 本文介绍一款基于JAVA开源的mongodb jdbc驱动为基础的无缝与springbootmybatis融合使用案例 mongodb JDBC 使用案例 https://blog.csdn.net/gongbing798930123/article/details/135002530 《基于开源的JA…...

freeRTOS使用

创建第一个FreeRTOS程序 1、官网源码下载 &#xff08;1&#xff09;进入FreeRTOS官网FreeRTOS professional services for application and RTOS development and consulting. FreeRTOS is an Open Source Code RTOS &#xff08;2&#xff09;点击下载FreeRTOS 2、处理目录 &…...

基于vue的线上点餐系统论文

基于vue的线上点餐系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了线上点餐系统的开发全过程。通过分析线上点餐系统管理的不足&#xff0c;创建了一个计算机管理线上点餐系统的方案。文章介绍了线上点餐…...

【Windows】windows11右键默认显示更多选项的办法

Windows11系统的右键菜单显示&#xff0c;需要多点一次“显示更多选项”才能看到所有菜单内容&#xff0c;按下面步骤简单设置一下就能恢复成Windows经典的右键菜单显示。 1. 2.输入命令【reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a…...

推荐使用过很好用的api,含免费次数

IP归属地-IPv4城市级&#xff1a;根据IP地址查询归属地信息&#xff0c;支持到城市级&#xff0c;包含国家、省、市、和运营商等信息。IP归属地-IPv6城市级&#xff1a;根据IP地址&#xff08;IPv6版本&#xff09;查询归属地信息&#xff0c;支持到中国大陆地区&#xff08;不…...

QT最大线程并发

声明一个处理函数;int timeTask(); 头文件&#xff1a; #include <QtConcurrent> #include <QFuture> 并发处理改函数的任务&#xff0c;直到处理完成&#xff1a; QFuture<int> ft QtConcurrent::run(this, &ch72_concurrent::timeTask);while (!f…...

在金属/绝缘体/p-GaN栅极高电子迁移率晶体管中同时实现大的栅压摆幅和增强的阈值电压稳定性

标题&#xff1a;Simultaneously Achieving Large Gate Swing and Enhanced Threshold Voltage Stability in Metal/Insulator/p-GaN Gate HEMT (IEDM2023) 摘要 摘要&#xff1a;对于增强型GaN功率晶体管的发展&#xff0c;栅压摆幅和阈值电压稳定性通常是互相排斥的。本文展…...

Redis第1讲——入门简介

Java并发编程的总结和学习算是告一段落了&#xff0c;这段时间思来想去&#xff0c;还是决定把Redis再巩固和学习一下。毕竟Redis不论是在面试还是实际应用中都是极其重要的&#xff0c;在面试中诸如Redis的缓存问题、热key、大key、过期策略、持久化机制等&#xff1b;还有在实…...

数据科学知识库

​ 我的博客是一个技术分享平台&#xff0c;涵盖了机器学习、数据可视化、大数据分析、数学统计学、推荐算法、Linux命令及环境搭建&#xff0c;以及Kafka、Flask、FastAPI、Docker等组件的使用教程。 在这个信息时代&#xff0c;数据已经成为了一种新的资源&#xff0c;而机…...

设计模式——责任链模式(行为模式)

引言 责任链模式是一种行为设计模式&#xff0c; 允许你将请求沿着处理者链进行发送。 收到请求后&#xff0c; 每个处理者均可对请求进行处理&#xff0c; 或将其传递给链上的下个处理者。 问题 假如你正在开发一个在线订购系统。 你希望对系统访问进行限制&#xff0c; 只允…...

【谭浩强C语言:前八章编程题(多解)】

文章目录 第一章1. 求两个整数之和(p7) 第二章2. 求三个数中的较大值&#xff08;用函数&#xff09;(p14、p107)3.求123...n(求n的阶乘&#xff0c;用for循环与while循环)(P17)1.循环求n的阶乘2.递归求n的阶乘(n< 10) 4.有M个学生&#xff0c;输出成绩在80分以上的学生的学…...

程序人生15年人生感悟

计算机程序员并不是一件什么高大上的职业。而仅仅是一份普通的工作。就像医生能治病救人&#xff0c;我们能治蓝屏救程序&#xff0c;我们都在为这个世界默默的做出自己的贡献。刻意或无意宣扬某个职业高大上&#xff0c;其实质是对其它行业从业者的不公平。但是有些人却常常这…...

React与AJAX

大家好&#xff0c;欢迎来到 《React与AJAX》 课程。在这一课中&#xff0c;我们将学习如何在 React 中使用 AJAX。 什么是 AJAX&#xff1f; AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;是一种使用 JavaScript 在浏览器和服务器之间进行异步通信的技术。A…...

C++ STL泛型算法

泛型算法 <algorithm>定义了大约 80 个标准算法。 它们操作由一对迭代器定义的&#xff08;输入&#xff09;序列或单一迭代器定义的&#xff08;输出&#xff09;序列。 当对两个序列进行拷贝、比较操作时&#xff0c;第一个序列由一对迭代器[b,e)表示&#xff0c;但第…...

使用OpenSSL生成PKCS#12格式的证书和私钥

要使用OpenSSL生成PKCS12格式的证书和私钥&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 安装OpenSSL 首先&#xff0c;确保已在计算机上安装了OpenSSL。可以从OpenSSL官方网站&#xff08;https://www.openssl.org/&#xff09;下载并安装适用于您的操作系统的版本。…...

超详细 | 哈里斯鹰优化算法原理、实现及其改进与利用(Matlab/Python)

测试函数为F9 在MATLAB中执行程序结果如下&#xff1a; 在Python中执行程序结果如下&#xff1a; 哈里斯鹰优化算法(Harris Hawks Optimization , HHO)是 Heidari等[1]于2019年提出的一种新型元启发式算法&#xff0c;设计灵感来源于哈里斯鹰在捕食猎物过程中的合作行为以及突…...

git 切换远程地址分支 推送到指定地址分支 版本回退

切换远程地址 1、切换远程仓库地址&#xff1a; 方式一&#xff1a;修改远程仓库地址 【git remote set-url origin URL】 更换远程仓库地址&#xff0c;URL为新地址。 git remote set-url https://gitee.com/xxss/omj_gateway.git 方式二&#xff1a;先删除远程仓库地址&…...

YOLOv3-YOLOv8的一些总结

0 写在前面 这个文档主要总结YOLO系列的创新点&#xff0c;以YOLOv3为baseline。参考(抄)了不少博客&#xff0c;就自己看看吧。有些模型的trick不感兴趣就没写进来&#xff0c;核心的都写了。 YOLO系列的网络都由四个部分组成&#xff1a;Input、Backbone、Neck、Prediction…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...