You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot多查询分页去重后分页失效的解决方案咨询

问题根源

你当前的逻辑是先对两个表分别分页查询,再合并去重,这会导致去重后的数据量小于分页预期(比如每页10条,去重后只剩8条),分页逻辑自然失效。核心问题是分页时机错误,应该先拿到所有符合条件的唯一数据标识,再对这些标识分页,最后查询对应数据。

解决方案

方案一:内存处理(适用于数据量不大的场景)

  1. 获取所有唯一ID:分别从两个表查询符合条件的kycTicketId,合并后去重得到唯一ID集合。
  2. 对ID分页:根据分页参数(页码、每页大小)截取ID列表的对应片段。
  3. 查询分页后的完整数据:根据分页后的ID,从两个表查询对应的DTO,再合并去重返回。

代码示例:

// 1. 从两个表获取所有符合条件的kycTicketId
Set<String> highRiskIds = customerKyc.findHighRiskL1ReturnedIds(startDateTime, endDateTime, agentIds);
Set<String> amlPositiveIds = customerKyc.findAmlPositiveL1ReturnedIds(startDateTime, endDateTime, agentIds);

// 合并去重得到唯一ID列表
Set<String> uniqueTicketIds = new HashSet<>();
uniqueTicketIds.addAll(highRiskIds);
uniqueTicketIds.addAll(amlPositiveIds);
List<String> ticketIdList = new ArrayList<>(uniqueTicketIds);

// 2. 执行分页逻辑(pageNum为当前页码,pageSize为每页条数)
int start = (pageNum - 1) * pageSize;
int end = Math.min(start + pageSize, ticketIdList.size());
if (start >= ticketIdList.size()) {
    return Collections.emptyList();
}
List<String> paginatedIds = ticketIdList.subList(start, end);

// 3. 根据分页后的ID查询完整DTO数据
List<L1ComplianceResponseDTO> highRiskCust = customerKyc.getL1ComplianceByIds(paginatedIds, "highRisk");
List<L1ComplianceResponseDTO> amlPositiveCust = customerKyc.getL1ComplianceByIds(paginatedIds, "amlPositive");

// 合并去重得到最终结果
List<L1ComplianceResponseDTO> finalResult = Stream.concat(highRiskCust.stream(), amlPositiveCust.stream())
        .filter(distinctByKey(L1ComplianceResponseDTO::getKycTicketId))
        .collect(Collectors.toList());

方案二:数据库层面分页(适用于大数据量场景)

直接在数据库通过UNION查询去重后的kycTicketId并分页,再根据这些ID查询完整数据,避免内存处理大量数据。

  1. DAO层添加联合分页查询ID的方法:
@Query(value = "SELECT kyc_ticket_id FROM high_risk_table WHERE create_time BETWEEN :start AND :end AND agent_id IN :agentIds " +
               "UNION " +
               "SELECT kyc_ticket_id FROM aml_positive_table WHERE create_time BETWEEN :start AND :end AND agent_id IN :agentIds " +
               "LIMIT :pageSize OFFSET :offset", nativeQuery = true)
List<String> findUniqueTicketIds(@Param("start") LocalDateTime start, 
                                 @Param("end") LocalDateTime end, 
                                 @Param("agentIds") List<String> agentIds,
                                 @Param("pageSize") int pageSize,
                                 @Param("offset") int offset);
  1. 业务层调用并查询完整数据:
// 计算分页偏移量
int offset = (pageNum - 1) * pageSize;
// 获取分页后的唯一ID
List<String> paginatedIds = customerKyc.findUniqueTicketIds(startDateTime, endDateTime, agentIds, pageSize, offset);
// 根据ID查询完整DTO(逻辑同方案一的步骤3)
List<L1ComplianceResponseDTO> highRiskCust = customerKyc.getL1ComplianceByIds(paginatedIds, "highRisk");
List<L1ComplianceResponseDTO> amlPositiveCust = customerKyc.getL1ComplianceByIds(paginatedIds, "amlPositive");

List<L1ComplianceResponseDTO> finalResult = Stream.concat(highRiskCust.stream(), amlPositiveCust.stream())
        .filter(distinctByKey(L1ComplianceResponseDTO::getKycTicketId))
        .collect(Collectors.toList());
关键注意事项
  • 优先使用数据库层面的联合分页,避免内存处理大量数据导致性能问题。
  • 确保distinctByKey方法是正确的去重逻辑(比如基于kycTicketId的哈希和相等判断)。
  • 如果使用Spring Data JPA的Pageable,可以将ID的分页结果封装为Page对象,方便统一返回分页信息(总条数、总页数等)。

内容的提问来源于stack exchange,提问作者Ritvik Khanijo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 17:55:22