JPA中TypedQuery调用getResultList后removeAll不生效问题求助
问题原因
- 每次调用
typedQuery.getResultList()都会重新执行SQL查询,返回一个全新的结果集合实例。你调用removeAll修改的是第一次调用返回的临时集合,后续再调用getResultList()拿到的是重新从数据库查出来的原始结果,之前的修改完全不生效。 - 分页参数是在二次过滤之后才设置到
typedQuery上的,最后执行查询拿结果的时候,相当于跳过了之前的二次过滤逻辑,直接拿了数据库查询的分页结果。 - 如果
ModelEntity类没有重写equals()和hashCode()方法,removeAll方法会默认按对象内存地址判断是否匹配,也可能导致删除失效。
解决方案
方案1:本地集合二次过滤(兼容所有数据库)
直接把查询结果先存到本地集合,所有过滤、分页操作都在本地集合上执行,避免反复触发数据库查询,修改后代码如下:
CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<ModelEntity> query = builder.createQuery(ModelEntity.class); Root<ModelEntity> root = query.from(ModelEntity.class); List<Predicate> listWhere = new ArrayList<>(); if(!Strings.isNullOrEmpty(param.getAccountNumber())){ listWhere.add(builder.like(root.get("accountNumber"), "%"+param.getAccountNumber()+"%")); } TypedQuery<ModelEntity> typedQuery = em.createQuery(query .where(listWhere.toArray(new Predicate[] {})) .orderBy(builder.desc(root.get("createdDate"))) ); // 先执行查询把结果存到本地集合,避免反复调用getResultList List<ModelEntity> allResult = typedQuery.getResultList(); Integer total = allResult.size(); List<ModelEntity> result = new ArrayList<>(); // 二次过滤逻辑 if(!Strings.isNullOrEmpty(param.getAccountNumber()) && total > 0){ List<ModelEntity> filteredResult = new ArrayList<>(); for(ModelEntity data : allResult){ boolean match = false; if (!Strings.isNullOrEmpty(data.getAccountNumber())) { List<String> accountNumbers = Arrays.asList(data.getAccountNumber().split(",")); if(accountNumbers.contains(param.getAccountNumber())){ match = true; } } if(match){ filteredResult.add(data); } } allResult = filteredResult; total = allResult.size(); } // 分页逻辑改到本地集合执行 if(total > 0){ int start = paging.getRowPerPage() * (paging.getPage() - 1); int end = Math.min(start + paging.getRowPerPage(), total); if(start < total){ result = allResult.subList(start, end); } }
方案2:数据库层面精准查询(效率更高,以MySQL为例)
如果使用MySQL数据库,可以直接用find_in_set函数在查询时就完成逗号分隔值的精准匹配,不需要二次过滤,修改查询条件即可:
if(!Strings.isNullOrEmpty(param.getAccountNumber())){ // 直接匹配逗号分隔的账号,不需要like和后续二次过滤 listWhere.add(builder.function("find_in_set", Integer.class, builder.literal(param.getAccountNumber()), root.get("accountNumber") ).greaterThan(0)); }
内容的提问来源于stack exchange,提问作者hirarqi
相关产品推荐
相关产品推荐

