多线程分片锁机制通过业务维度拆分数据并为每分片分配独立锁,避免全局串行与主键冲突;支持本地concurrenthashmap+reentrantlock(单体)和redis分布式锁(多节点)两种实现,均需配合数据库唯一索引与前端batchtoken幂等控制。

多线程分片锁机制不是直接“锁住整个导入过程”,而是把一批数据按业务维度(比如主键前缀、ID取模、时间分段等)拆成多个逻辑子集,每个子集由独立线程处理,并为每个子集分配专属锁。这样既避免全局串行,又防止同一分片内并发插入重复主键。
按主键哈希分片 + 本地锁控制
适用于单体应用、批量数据可预知主键范围的场景。核心是让相同主键归属同一分片,再用 ConcurrentHashMap + ReentrantLock 管理分片锁。
- 将主键(如 order_no)做哈希或取模:shardKey = orderNo.hashCode() % N(N 通常取 8、16、32),确保同主键始终落到同一分片
- 用 ConcurrentHashMap
预热创建 N 个分片锁,key 是 shardKey,value 是 new ReentrantLock() - 每个线程处理自己分片的数据前,先 lock.lock();处理完必须 finally unlock()
- 锁内执行「查是否存在 → 不存在则插入」,或直接 insert ignore / on duplicate key update
基于 Redis 的分片分布式锁
适用于多节点部署、主键无固定规律、需跨 JVM 协调的场景。关键在于锁 key 必须体现「分片粒度 + 业务唯一性」。
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
- 构造分片锁 key:"import:shard:" + (id % 100)(按主键取模分 100 片),或更业务化的 "import:user:" + userId % 16
- 使用 SET key value NX PX 30000 获取锁,value 用 UUID 防误删
- 加锁成功后,在该分片内执行幂等校验(如查表 or Redis SETNX 标记已处理 ID)+ 插入
- 务必用 Lua 脚本释放锁,避免锁被其他线程误删
数据库唯一约束 + 降级兜底
无论是否加锁,都必须在数据库主键或业务唯一字段(如 order_no、batch_id + seq)上建 UNIQUE 索引。这是最可靠的一道防线。
- 插入时捕获 MySQLIntegrityConstraintViolationException 或对应数据库唯一冲突异常
- 统一转为友好提示(如“第X条数据已存在,跳过导入”),不抛出 500
- 注意:不能只依赖此方式,因为异常抛出意味着已有重复请求穿透了前置锁,说明锁设计或 key 粒度有问题
结合前端 token 的批量幂等控制
针对用户手动触发的批量导入(如 Excel 上传),建议前后端协同增强幂等性。
- 前端上传前生成唯一 batchToken(如 UUID),携带在请求 header 或 body 中
- 后端收到后,先用 Redis SETNX batchToken 1 EX 300 标记该批次已开始处理
- 若 setnx 失败,直接返回“该批次正在处理中,请勿重复提交”
- 后续每条记录插入前,仍按分片锁 + 唯一索引双保险执行
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










