怎么解决java并发请求下数据插入重复问题
发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,本篇内容介绍了"怎么解决java并发请求下数据插入重复问题"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所
千家信息网最后更新 2025年11月07日怎么解决java并发请求下数据插入重复问题
本篇内容介绍了"怎么解决java并发请求下数据插入重复问题"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
前言
前段时间发现数据库里经常会存在两条相同的用户数据,导致数据查询异常。查了原因,发现前端微信小程序在授权登录时,有时会出现同时发送了两条一模一样的请求(也就是常说的并发)。虽然后端代码有做防重复的判断,但是避免不了并发时候的重复性操作。于是就开始考虑并发的解决方案,解决方案有很多,从拦截请求到数据库层面都可以入手。
我们采用了对请求报文生成摘要信息+Redis分布式锁的方案。运行了一段时间,功能很可靠,代码也很简洁。于是上来做下记录以便后续参考。
解决方案说明:
系统架构用的Spring boot,定义一个Filter过滤器对请求进行过滤,然后对请求报文生成摘要信息并设置Redis分布式锁。通过摘要和锁判断是否为同一请求。
分布式锁工具类
public class ContextLJ { private static final Integer JD = 0; /** * 上锁 使用redis 为分布式项目 加锁 * @param sign * @param tiD * @return * @throws Exception */ public static boolean lock(String sign, String tiD) { synchronized (JD) { // 加锁 Cache cache = CacheManager.getCommonCache(sign); if(cache == null || StringUtils.isBlank(cache.getValue())) { CacheManager.putCommonCacheInfo(sign, tiD, 10000); return true; } return false; } } /** * 锁验证 * @param sign * @param tiD * @return */ public static boolean checklock(String sign, String tiD){ Cache cache = CacheManager.getCommonCache(sign); String uTid = StringUtils.replace(cache.getValue(), "\"", ""); return tiD.equals(uTid); } /** * 去掉锁 * @param sign * @param tiD */ public static void clent (String sign, String tiD){ if (checklock(sign, tiD)) { CacheManager.clearOnly(sign); } } /** * 获取摘要 * @param request */ public static String getSign(ServletRequest request){ // 此工具是将 request中的请求内容 拼装成 key=value&key=value2 的形式 源码在线面 String sign = null; try { Map map = getRequstMap((HttpServletRequest) request); // 生成摘要 sign = buildRequest(map); } catch (Exception e) { e.printStackTrace(); } return sign; } public static Map getRequstMap(HttpServletRequest req) throws Exception{ Map params = new HashMap(); params.put("uri", req.getRequestURI()); Map requestParams = req.getParameterMap(); for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } params.put(name, valueStr); } return params; } private static String buildRequest(Map map) { List signList = new ArrayList<>(); for(Entry entry : map.entrySet()) { signList.add(entry.getKey() + "=" + entry.getValue()); } String sign = StringUtils.join(signList, "&"); return DigestUtils.md5Hex(sign); } } 在过滤器实现请求拦截
/** * 过滤频繁请求 */@Slf4j@Componentpublic class MyFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse myResp, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; Boolean isDict = StringUtils.contains(req.getRequestURI(), "/dict/getDatas"); Boolean isFile = StringUtils.contains(req.getRequestURI(), "/files/file"); if(isDict || isFile) { chain.doFilter(request, myResp); // 查询数据字典或者文件,直接放行 return; } String sign = "sign_" + ContextLJ.getSign(request); // 生成摘要 String tiD = RandomUtils.randomCode(3) + "_" + Thread.currentThread().getId(); // 当前线程的身份 try { if (!ContextLJ.lock(sign, tiD)) { Map map = ContextLJ.getRequstMap((HttpServletRequest)request); log.warn("放弃相同并发请求【" + sign+ "】【" + tiD+"】"+JSON.toJSONString(map)); frequentlyError(myResp); return; } if (!ContextLJ.checklock(sign, tiD)) { Map map = ContextLJ.getRequstMap((HttpServletRequest)request); log.warn("加锁验证失败 【" + sign+ "】【" + tiD+"】"+JSON.toJSONString(map)); frequentlyError(myResp); return; } chain.doFilter(request, myResp); // 放行 } catch (Exception e) { // 捕获到异常 进行异常过滤 log.error("", e); myResp.getWriter().write(JSON.toJSONString(ApiRs.asError("服务器繁忙,请重试"))); } finally { ContextLJ.clent(sign, tiD); } } @Override public void destroy() { } /** * 频繁请求 */ private void frequentlyError(ServletResponse myResp) throws IOException { ((HttpServletResponse) myResp).setHeader("Content-type", "text/html;charset=UTF-8"); myResp.getWriter().write(JSON.toJSONString(ApiRs.asError("稍安勿躁,不要频繁请求"))); }} "怎么解决java并发请求下数据插入重复问题"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
数据
摘要
分布式
方案
生成
频繁
内容
解决方案
问题
相同
代码
信息
工具
报文
数据库
时间
更多
知识
过滤器
查询
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
nosql支持数据库吗
安防监控平台管理服务器
深圳市委宣传部网络安全
香港服务器租赁
数据库收录作品欣赏
网络安全风险评估标准依据
gis 数据库下载
淄博管理软件开发服务公司
数据库连接视频
常熟电子网络技术市场价格
公司网络安全观
单机手游需不需要服务器
上海服务器报废单价
吃鸡服务器安装教程
数据库查询大于张三的员工信息表
盛皓互联网科技工作室
服务器的安全问题有哪些
固定式读码器的柔性软件开发
pg库给数据库的序列授权
网络安全青年博士论坛
为什么叫高斯数据库
pjsip服务器
上海安全云端存储服务器
千钧互动网络技术
服务器进入硬盘启动项
嵌入式软件开发导论免费完整版
加强对数据库安全的认识
索尼电视双影像数据库
网络安全题库及答案多选
连接u8数据库服务器失败