hashset去重核心是先加载已有主键到hashset,再用o(1)的contains()过滤重复,避免异常捕获或反复查库;需注意线程安全、缓存时效及大数据量时改用布隆过滤器。

用 HashSet 快速过滤数据库重复主键,核心思路是:**先查出已存在的主键集合,再用 HashSet 做 O(1) 判重,避免逐条 INSERT 时触发唯一约束异常或反复查库**。这不是替代数据库唯一约束,而是应用层前置去重,提升批量插入/更新效率。
提前加载已有主键到 HashSet
在批量操作前,一次性查询数据库中当前已存在的主键(如 id 或业务唯一码),存入 HashSet:
List<long> existingIds = jdbcTemplate.query("SELECT id FROM user",
(rs, rowNum) -> rs.getLong("id"));
Set<long> idSet = new HashSet(existingIds);</long></long>
注意:数据量大时加 LIMIT 不适用;若主键量超百万,考虑分页加载或改用布隆过滤器(但需接受极小误判率)。
批量插入前用 contains() 过滤重复
对要插入的新数据列表,先检查主键是否已在 HashSet 中,跳过重复项:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
不重复的才加入待插入列表:
if (!idSet.contains(newUser.getId())) { validUsers.add(newUser); } - 过滤后直接执行批量插入(如
jdbcTemplate.batchUpdate(...)),避免因主键冲突导致整批失败 - 若业务允许“覆盖更新”,可改为先 delete 再 insert,或用
INSERT ... ON DUPLICATE KEY UPDATE(MySQL)
注意线程安全与数据一致性
HashSet 本身非线程安全,多线程场景下:
- 若只读(加载后不再修改),用
Collections.unmodifiableSet()更安全 - 若需动态更新(如边写入边维护),改用
ConcurrentHashMap.newKeySet()(Java 8+)替代 HashSet - 务必考虑缓存时效性——如果其他服务也在写同一张表,需配合数据库 binlog、消息队列或短 TTL 缓存来同步主键状态
比 try-catch 主键冲突更高效
有人用 try { insert... } catch (DuplicateKeyException e) { } 实现去重,但:
- 异常机制开销大,频繁抛异常会显著拖慢性能
- 无法预知哪条重复,不利于日志记录和业务反馈
- 事务中抛异常可能导致部分成功、部分回滚,逻辑难控制
而 HashSet 判重是纯内存操作,毫秒级完成,可控、可审计、无副作用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










