如何避免使用collection fetch指定的警告“firstResult / maxResults; 在内存中应用!“在使用Hibernate时?

我在服务器日志中收到警告“使用集合提取指定的firstResult / maxResults;在内存中应用!” 。 但一切正常。 但我不想要这个警告。

我的代码是

public employee find(int id) { return (employee) getEntityManager().createQuery(QUERY).setParameter("id", id).getSingleResult(); } 

我的疑问是

 QUERY = "from employee as emp left join fetch emp.salary left join fetch emp.department where emp.id = :id" 

此警告的原因是,当使用提取连接时,结果集中的顺序仅由所选实体的ID定义(而不是通过连接提取)。

如果内存中的这种排序导致问题,请不要将firsResult / maxResults与JOIN FETCH一起使用。

要避免这种警告,你必须将调用getSingleResult更改为getResultList().get(0)

虽然您获得了有效的结果,但SQL查询会获取所有数据,但效率并不高。

正如我在本文中解释的那样,您可以轻松地转换使用JOIN FETCH和分页的JPQL查询:

 List posts = entityManager.createQuery( "select p " + "from Post p " + "left join fetch p.comments " + "where p.title like :title " + "order by p.id", Post.class) .setParameter("title", titlePattern) .setMaxResults(maxResults) .getResultList(); 

进入SQL查询,使用父标识符使用DENSE_RANK限制结果:

 List posts = entityManager.createNativeQuery( "select p_pc_r.* " + "from ( " + " select *, dense_rank() OVER (ORDER BY post_id) rank " + " from ( " + " select p.*, pc.* " + " from post p " + " left join post_comment pc on p.id = pc.post_id " + " where p.title like :title " + " order by p.id " + " ) p_pc " + ") p_pc_r " + "where p_pc_r.rank <= :rank", Post.class) .setParameter("title", titlePattern) .setParameter("rank", maxResults) .unwrap( NativeQuery.class ) .addEntity( "p", Post.class ) .addEntity( "pc", PostComment.class ) .setResultTransformer( DistinctPostResultTransformer.INSTANCE ) .getResultList(); 

要将表格结果集转换回实体图,您需要一个ResultTransformer ,其外观如下所示:

 public class DistinctPostResultTransformer extends BasicTransformerAdapter { private static final DistinctPostResultTransformer INSTANCE = new DistinctPostResultTransformer(); @Override public List transformList(List list) { Map identifiableMap = new LinkedHashMap<>( list.size() ); for ( Object entityArray : list ) { if ( Object[].class.isAssignableFrom( entityArray.getClass() ) ) { Post post = null; PostComment comment = null; Object[] tuples = (Object[]) entityArray; for ( Object tuple : tuples ) { if(tuple instanceof Post) { post = (Post) tuple; } else if(tuple instanceof PostComment) { comment = (PostComment) tuple; } else { throw new UnsupportedOperationException( "Tuple " + tuple.getClass() + " is not supported!" ); } } Objects.requireNonNull(post); Objects.requireNonNull(comment); if ( !identifiableMap.containsKey( post.getId() ) ) { identifiableMap.put( post.getId(), post ); post.setComments( new ArrayList<>() ); } post.addComment( comment ); } } return new ArrayList<>( identifiableMap.values() ); } } 

而已!

问题是你会得到笛卡尔积的JOIN。 偏移将削减您的记录集,而不会查看您是否仍在相同的根身份类

我想emp有许多部门,这是一对多的关系。 Hibernate将使用获取的部门记录为此查询获取许多行。 因此,在将结果真正提取到内存之前,无法确定结果集的顺序。 所以分页将在记忆中完成。

如果您不想使用emp获取部门,但仍希望根据部门进行某些查询,则可以在不显示警告的情况下实现结果(不在内存中进行排序)。 为此,您只需删除“fetch”子句。 所以类似如下:

QUERY =“从员工身份离开加入emp.salary sal left join emp.department dep其中emp.id =:id和dep.name =’testing’和sal.salary> 5000”