Spring Boot多查询分页去重后分页失效的解决方案咨询
问题根源
你当前的逻辑是先对两个表分别分页查询,再合并去重,这会导致去重后的数据量小于分页预期(比如每页10条,去重后只剩8条),分页逻辑自然失效。核心问题是分页时机错误,应该先拿到所有符合条件的唯一数据标识,再对这些标识分页,最后查询对应数据。
解决方案
方案一:内存处理(适用于数据量不大的场景)
- 获取所有唯一ID:分别从两个表查询符合条件的
kycTicketId,合并后去重得到唯一ID集合。 - 对ID分页:根据分页参数(页码、每页大小)截取ID列表的对应片段。
- 查询分页后的完整数据:根据分页后的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查询完整数据,避免内存处理大量数据。
- 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);
- 业务层调用并查询完整数据:
// 计算分页偏移量 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
相关产品推荐
相关产品推荐

