
本文介绍如何在 Spring Data JPA 分页查询返回的 Object[] 结果集中,基于 tid 字段实现内存级去重,确保每个 tid 仅保留一条记录,并给出线程安全、可维护的实现方案。
本文介绍如何在 spring data jpa 分页查询返回的 `object[]` 结果集中,基于 `tid` 字段实现内存级去重,确保每个 `tid` 仅保留一条记录,并给出线程安全、可维护的实现方案。
在使用 Page<object></object> 接收多表关联查询结果(如 onetable 和 twotable)时,数据库原始结果常因 JOIN 导致同一 tid 出现多次。由于 SQL 层面难以直接 DISTINCT ON (tid)(尤其在 H2/MySQL 等不支持该语法的数据库中),推荐在 Java 层进行高效、可控的逻辑去重。
核心思路是:利用 Set<long></long> 缓存已处理的 tid 值,借助 Set.add() 方法的返回值(true 表示新增成功、即首次出现)判断唯一性。以下是优化后的完整实现:
Page<Object[]> datasetresults = repository.findtest(tid,
PageRequest.of(page, per_page, Sort.by(s, sort)));
Set<Long> seenTids = ConcurrentHashMap.newKeySet(); // 线程安全,适合并发场景
List<TestBean> distinctResults = new ArrayList<>();
for (Object[] row : datasetresults.getContent()) {
// 安全校验:确保数组长度足够且元素类型匹配
if (row.length < 2 || !(row[0] instanceof onetable) || !(row[1] instanceof twotable)) {
continue;
}
onetable t1 = (onetable) row[0];
twotable t2 = (twotable) row[1];
Long currentTid = t1.getTid();
if (currentTid == null) continue;
// 利用 Set.add() 的原子性判断是否为首个 tid
if (seenTids.add(currentTid)) {
TestBean bean = new TestBean();
bean.setTid(currentTid);
bean.setName(t1.getName()); // 示例字段映射
bean.setDesc(t2.getDescription());
distinctResults.add(bean);
}
}
// distinctResults 即为 tid 唯一的结果列表关键注意事项:
- ✅ 优先使用
ConcurrentHashMap.newKeySet()替代HashSet:当代码运行于多线程分页请求环境(如 Web 应用)时,避免HashSet引发的ConcurrentModificationException; - ✅ 显式判空与类型校验:防止
ClassCastException或NullPointerException,提升健壮性; - ⚠️ 注意分页语义:此方式是对 当前页内 的结果去重。若需跨页全局去重(如第1页和第2页含相同
tid),需改用数据库层GROUP BY tid或自定义@Query配合DISTINCT,并调整分页逻辑; - ? 性能提示:对于超大数据集(单页 > 10,000 条),建议将去重逻辑下沉至数据库(如 PostgreSQL 的
DISTINCT ON (tid)或 MySQL 8.0+ 的窗口函数),Java 层去重更适合中小规模场景。
综上,该方案以最小侵入性、高可读性达成业务所需的 tid 维度唯一性控制,是 Spring Boot 项目中处理关联查询去重的典型实践。
立即学习“Java免费学习笔记(深入)”;


















