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

高并发下的重复记录之谜:从前端到数据库的全方位排查

在实际开发中,我们经常会遇到这样的场景:需要为某类业务生成唯一序列号(比如订单号、需求编号等),并且要求在高并发场景下保证唯一性。最近团队就遇到了一个典型问题:前端通过 for 循环快速提交POST请求时,后端生成的序列号出现了重复记录,且重复记录的year,month,day,flowCode完全相同。

我们从问题出发,深入分析背后的技术原理,理解为什么会出现重复、@Transactional注解为何 会“失效”,以及如何彻底解决这类问题。

一、现象回顾:重复记录是如何产生的?

先简单描述一下业务场景:后端有一个getAndIncrementSeq方法,用于根据year,month,day,flowCode(年月日 + 业务类型)生成自增序列号。逻辑是:

  1. 先查询数据库中是否存在该组合的记录;
  2. 若存在,则将currentSeq字段 + 1 并更新;
  3. 若不存在,则插入一条新记录(初始currentSeq=1)。

前端在某个操作中,通过for循环连续提交了多个 POST 请求(比如一次性创建 5 条同类型记录),结果发现数据库中出现了两条year,month,day,flowCode完全相同的记录,导致序列号重复。

二、问题根源剖析:从并发到数据库的 “漏洞”

1. 前端快速提交:高并发的 “催化剂”

前端使用for循环提交POST请求时,会出现一个关键问题:请求之间几乎没有时间间隔

  • 正常情况下,用户手动操作的请求间隔较长,并发冲突概率低;
  • for循环提交会在毫秒级甚至更短的时间内触发多个同类型请求,后端会同时启动多个线程处理这批请求,将系统推入高并发场景。

这些线程会同时执行getAndIncrementSeq方法,为后续的冲突埋下伏笔。

2. @Transactional的 “局限性”:原子性≠并发安全性

后端方法上标注了@Transactional,但为什么还会出问题?

@Transactional的核心作用是保证事务内操作的原子性(要么全成功,要么全回滚),但它无法直接解决 “并发写入冲突”,原因有两点:

  • 事务隔离级别的影响:数据库默认隔离级别(如PostgreSQL的READ COMMITTED)下,事务使用 “快照读”。假设线程 A 和线程 B 同时开始事务:

    • 线程 A 查询(year, month, day, flowCode),发现记录不存在;
    • 线程 B 在同一时间查询,由于线程 A 的插入操作尚未提交(事务未结束),线程 B 的快照中也看不到这条记录,同样认为 “记录不存在”。
  • 并发可见性问题:事务的原子性仅保证 “操作不中断”,但不能强制让多个并发事务 “互相可见” 未提交的操作。因此,即使有@Transactional,多个线程仍可能因 “查询盲区” 而重复执行插入逻辑。

3. 解决方法:构建唯一索引—— “最后一道防线”

在数据库表中(year, month, day, flowCode)字段上建立唯一索引

  • 若没有唯一索引:当线程 A 和线程 B 同时插入记录时,数据库不会对这四个字段的组合进行唯一性校验,两条完全相同的记录会被同时写入表中。

  • 若有唯一索引:数据库会自动拦截重复插入操作(触发异常)。此时,若代码中实现了重试机制(如检测到唯一冲突后重新查询并更新),则后失败的线程会基于已存在的记录递增序列号,避免重复。

三、终极解决方案:三层防护机制

要彻底解决高并发下的重复记录问题,需要从 “前端控制 + 后端逻辑 + 数据库约束” 三个层面入手:

1. 前端:减少不必要的并发请求

  • 尽量避免使用for循环批量提交 POST 请求,改为通过一次性接口提交批量数据;
  • 若必须循环提交,可添加延迟(如setTimeout),降低请求并发度。

2. 后端:完善并发控制逻辑

  • 保留@Transactional:保证 “查询 - 插入 / 更新” 操作的原子性,避免中间状态导致的高并发数据不一致;
  • 强化重试机制:针对唯一索引冲突异常,增加重试逻辑(如最多重试 3 次),让失败的线程重新执行查询 - 更新流程;
  • 行锁控制:在查询时使用行锁,避免并发更新时的 “丢失更新” 的问题(适用于记录已存在的场景)。

3. 数据库:建立唯一索引,守住最后一道防线

最后的防线:建立唯一索引,强制数据库层面拒绝重复插入:有了唯一索引后,即使前端并发请求再多,后端事务隔离级别导致 “查询盲区”,数据库也会像一道 “防火墙”,拦截所有重复插入操作,配合后端重试机制即可保证序列号唯一。

四、总结:高并发下的数据唯一性保障

通过这个问题,我们可以总结出高并发场景下保证数据唯一性的核心原则:

  1. 数据库约束是底线:唯一索引 / 主键是防止重复的最后一道防线,不可省略;
  2. 事务是基础:保证操作原子性,仍需结合隔离级别理解其局限性;
  3. 重试机制是补充:针对并发冲突(如唯一索引冲突),通过重试让线程重新获取最新数据,避免重复;
  4. 前端优化是辅助:减少不必要的并发请求,降低前端重复请求压力。

希望以上能帮大家避开类似的坑,在高并发场景下写出更健壮的代码!

欢迎在评论区分享你的高并发踩坑经历,一起交流解决方案~

http://www.dtcms.com/a/581502.html

相关文章:

  • AI搜索时代品牌护城河:从“流量争夺”到“可信度竞争”的战略跃迁
  • 【推荐系统14】数据分析:以阿里天池新闻推荐为例学习
  • 安卓进阶——OpenGL ES
  • 做app动态界面的网站有哪些网站建设从哪入手
  • RV1126 NO.41:利用OPENCV的API计算轮廓面积
  • 15 langgraph基本组件
  • 网站开发答辩ppt上海网站排名
  • LeetCode 面试经典 150_二叉树_翻转二叉树(69_226_C++_简单)(DFS)
  • 【PLM实施专家宝典】离散制造企业ECO管理优化方案:构建自动化、零错误的变更引擎
  • go tool command
  • 网站流量如何做cms网站开发流程
  • HTML ASCII 编码解析与应用
  • Javascript函数之函数的参数以及默认参数?
  • LNMP部署及应用
  • 优质做网站哪家正规wordpress附件修复
  • Java-HTTP响应以及HTTPS(下)
  • [人工智能-大模型-135]:词向量的演进,对词向量的对Transformer架构理解的前提与关键。
  • 【1Panel】1、安装1Panel
  • JAVA:Spring Boot3 新特性解析的技术指南
  • 数据结构系列之十大排序算法
  • Spring Boot接收前端参数的注解总结
  • .c .o .a .elf .a2l hex map 这些后缀文件的互相之间的联系和作用
  • 纯静态网站seowordpress内页模板
  • 包装公司网站模板下载哈尔滨网络seo公司
  • 基于协同过滤算法的小说推荐系统_django+spider
  • VSCODE 插件 rust-analyzer 使用遇到的问题 快捷键查看定义
  • 个人网页设计制作网站模板西宁做网站制作的公司
  • Ubuntu24.10禁用该源...+vmware无法复制黏贴“天坑闭环”——从 DNS 诡异解析到 Ubuntu EOL 引发的 apt 404排除折腾记
  • npm i / npm install 卡死不动解决方法
  • 安装GPT4Free(也就是g4f)的最新版:g4f-6.5.7