我在 Criteria API 查询中实现了可分页功能,并且我注意到在查询执行期间内存使用量增加。我还使用 spring-data-jpa 方法查询来返回相同的结果,但是在处理完每个批次后都会清理内存。我尝试从 EntityManager 中分离、刷新、清除对象,但内存使用量会继续上升,偶尔会下降,但不如方法查询那么多。我的问题是,如果对象被分离,什么会导致这种内存使用以及如何处理它?
方法查询的内存使用情况:
代码
由于我也在更新从数据库中检索到的实体,因此我使用保存最后处理实体的 ID 的方法,因此当实体获得更新时,查询不会跳过下一个选定页面。下面我提供的代码示例并非来自我正在开发的真实应用程序,但它只是重现了我遇到的问题。
存储库代码:
@Override
public Slice<Player> getPlayers(int lastId, Pageable pageable) {
List<Predicate> predicates = new ArrayList<>();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Player> criteriaQuery = criteriaBuilder.createQuery(Player.class);
Root<Player> root = criteriaQuery.from(Player.class);
predicates.add(criteriaBuilder.greaterThan(root.get("id"), lastId));
criteriaQuery.where(criteriaBuilder.and(predicates.toArray(Predicate[]::new)));
criteriaQuery.orderBy(criteriaBuilder.asc(root.get("id")));
var query = entityManager.createQuery(criteriaQuery);
if (pageable.isPaged()) {
int pageSize = pageable.getPageSize();
int offset = pageable.getPageNumber() > 0 ? pageable.getPageNumber() * pageSize : 0;
// Fetch additional element and skip it based on the pageSize to know hasNext value.
query.setMaxResults(pageSize + 1);
query.setFirstResult(offset);
var resultList = query.getResultList();
boolean hasNext = pageable.isPaged() && resultList.size() > pageSize;
return new SliceImpl<>(hasNext ? resultList.subList(0, pageSize) : resultList, pageable, hasNext);
} else {
return new SliceImpl<>(query.getResultList(), pageable, false);
}
}
遍历可分页:
@Override
public Slice<Player> getAllPlayersPageable() {
int lastId = 0;
boolean hasNext = false;
Pageable pageable = PageRequest.of(0, 200);
do {
var players = playerCriteriaRepository.getPlayers(lastId, pageable);
if(!players.isEmpty()){
lastId = players.getContent().get(players.getContent().size() - 1).getId();
for(var player : players){
System.out.println(player.getFirstName());
entityManager.detach(player);
}
}
hasNext = players.hasNext();
} while (hasNext);
return null;
}

