当前位置: 首页 > 知识库问答 >
问题:

如何避免出现警告“使用集合获取指定的firstResult/maxResults;在内存中应用!”使用Hibernate时?

娄利
2023-03-14

我在服务器日志中收到一个警告“firstResult/max结果指定集合获取;在内存中应用!”。然而一切正常。但我不想要这个警告。

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"

共有3个答案

笪涛
2023-03-14

要避免此警告,必须将调用getSingleResult更改为getResultList()。获取(0)

葛宪
2023-03-14

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

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

施选
2023-03-14

虽然您得到了有效的结果,但SQL查询获取了所有数据,但它并没有达到应有的效率。

所以,你有两个选择。

解决此问题的最简单方法是执行两个查询:

.第一个查询将获取与提供的过滤条件匹配的根实体标识符。.第二个查询将使用之前提取的根实体标识符来获取父实体和子实体。

此方法非常容易实现,如下所示:

List<Long> postIds = entityManager
.createQuery(
    "select p.id " +
    "from Post p " +
    "where p.title like :titlePattern " +
    "order by p.createdOn", Long.class)
.setParameter(
    "titlePattern",
    "High-Performance Java Persistence %"
)
.setMaxResults(5)
.getResultList();
 
List<Post> posts = entityManager
.createQuery(
    "select distinct p " +
    "from Post p " +
    "left join fetch p.comments " +
    "where p.id in (:postIds) "  +
    "order by p.createdOn", Post.class)
.setParameter("postIds", postIds)
.setHint(
    "hibernate.query.passDistinctThrough", 
    false
)
.getResultList();

第二种方法是对符合筛选条件的父实体和子实体的结果集使用SDENSE\u RANK,并仅限制前N个post条目的输出。

SQL查询可以如下所示:

@NamedNativeQuery(
    name = "PostWithCommentByRank",
    query =
        "SELECT * " +
        "FROM (   " +
        "    SELECT *, dense_rank() OVER (ORDER BY \"p.created_on\", \"p.id\") rank " +
        "    FROM (   " +
        "        SELECT p.id AS \"p.id\", " +
        "               p.created_on AS \"p.created_on\", " +
        "               p.title AS \"p.title\", " +
        "               pc.id as \"pc.id\", " +
        "               pc.created_on AS \"pc.created_on\", " +
        "               pc.review AS \"pc.review\", " +
        "               pc.post_id AS \"pc.post_id\" " +
        "        FROM post p  " +
        "        LEFT JOIN post_comment pc ON p.id = pc.post_id " +
        "        WHERE p.title LIKE :titlePattern " +
        "        ORDER BY p.created_on " +
        "    ) p_pc " +
        ") p_pc_r " +
        "WHERE p_pc_r.rank <= :rank ",
    resultSetMapping = "PostWithCommentByRankMapping"
)
@SqlResultSetMapping(
    name = "PostWithCommentByRankMapping",
    entities = {
        @EntityResult(
            entityClass = Post.class,
            fields = {
                @FieldResult(name = "id", column = "p.id"),
                @FieldResult(name = "createdOn", column = "p.created_on"),
                @FieldResult(name = "title", column = "p.title"),
            }
        ),
        @EntityResult(
            entityClass = PostComment.class,
            fields = {
                @FieldResult(name = "id", column = "pc.id"),
                @FieldResult(name = "createdOn", column = "pc.created_on"),
                @FieldResult(name = "review", column = "pc.review"),
                @FieldResult(name = "post", column = "pc.post_id"),
            }
        )
    }
)

@NamedNativeQuery获取与提供的标题匹配的所有Post实体及其关联的PostComment子实体。DENSE_RANK窗口函数用于为每个Post和PostComment加入的记录分配排名,以便我们以后可以仅过滤我们有兴趣获取的Post记录的数量。

SqlResultSetMap提供SQL级列别名和需要填充的JPA实体属性之间的映射。

现在,我们可以按如下方式执行PostWithCommentByRank

List<Post> posts = entityManager
.createNamedQuery("PostWithCommentByRank")
.setParameter(
    "titlePattern",
    "High-Performance Java Persistence %"
)
.setParameter(
    "rank",
    5
)
.unwrap(NativeQuery.class)
.setResultTransformer(
    new DistinctPostResultTransformer(entityManager)
)
.getResultList();

现在,默认情况下,像PostWithCommentByRank这样的本机SQL查询将获取同一JDBC行中的Post和PostComment,因此我们最终将得到一个包含这两个实体的对象[]。

但是,我们想将表格Object[]数组转换为父子实体的树,因此,我们需要使用HibernateResultTransex

DistinctPostResultTransformer如下所示:

public class DistinctPostResultTransformer
        extends BasicTransformerAdapter {
 
    private final EntityManager entityManager;
 
    public DistinctPostResultTransformer(
            EntityManager entityManager) {
        this.entityManager = entityManager;
    }
 
    @Override
    public List transformList(
            List list) {
             
        Map<Serializable, Identifiable> 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 Identifiable) {
                        entityManager.detach(tuple);
 
                        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!"
                            );
                        }
                    }
                }
 
                if (post != null) {
                    if (!identifiableMap.containsKey(post.getId())) {
                        identifiableMap.put(post.getId(), post);
                        post.setComments(new ArrayList<>());
                    }
                    if (comment != null) {
                        post.addComment(comment);
                    }
                }
            }
        }
        return new ArrayList<>(identifiableMap.values());
    }
}

差异后结果转换器必须分离正在获取的实体,因为我们正在覆盖子集合并且我们不希望它作为实体状态转换传播:

post.setComments(new ArrayList<>());
 类似资料:
  • 问题内容: 我在服务器日志 “用集合获取指定的firstResult / maxResults;在内存中应用!”中 收到警告 。 。但是,一切正常。但我不要这个警告。 我的代码是 我的查询是 问题答案: 该警告的原因是,当使用访存联接时,结果集中的顺序仅由所选实体的ID定义(而不是由访存的联接定义)。 如果内存中的这种排序引起问题,请不要在JOIN FETCH中使用firsResult / max

  • 问题内容: 我在服务器日志 “用集合获取指定的firstResult / maxResults;在内存中应用!”中 收到警告 。 。但是,一切正常。但我不要这个警告。 我的代码是 我的查询是 问题答案: 该警告的原因是,当使用访存联接时,结果集中的顺序仅由所选实体的ID定义(而不是由访存的联接定义)。 如果内存中的这种排序引起问题,请不要在JOIN FETCH中使用firsResult / max

  • 问题内容: 我遇到了一个问题,我在JPA中有一个查询。因为我有一些集合,所以我需要使用左连接获取或内部连接获取 我的问题是使用和,以便带回准确的结果数。每次我看到整个结果都带回来,并且只有在使用maxResult之后。 有什么办法可以使maxResult之前吗? 非常感谢 ! 这是更多信息: 我的问题是当我使用它时: 我在日志中看到此消息: 2011年6月7日09:52:37 org.hibern

  • 问题内容: 使用createQuery()。list之后是否可以避免投射警告? 我希望找到一种通过通用参数或方法参数指定目标对象的方法,如下所示: 问题答案: 要记住的最重要的一点是, 警告是由于编译器引起的,而不是hibernate的 -您可以告诉编译器忽略未实现的泛型。通过使用HQL,我们以一种类型安全的方式查询数据,不幸的是,java无法进行验证。 有很多方法可以避开hibernate转换的

  • 嘿,我最近开始编写一个不和谐机器人。但是现在我有一个问题。我试图得到一个角色反应,但不知何故,我一直得到错误。我要把你的错误和我的代码联系起来,这样也许有人能帮我。 警告:https://hastebin.com/ativekefod.sql MessageReactionaddEvent.js:https://hastebin.com/nababomuta.js 谢谢你的帮助!

  • 我试图在一个非常简单的Hibernate示例中填充一些实体对象。我的数据库由两个表组成,“Departments”(Id,Name)和“Employees”(Id,DepartmentsId,FirstName,LastName)。我的SQL查询只是员工到部门的左连接。 我已经按照Hibernate文档中的规定设置了注释,但每当我尝试序列化实体时,Hibernate就会进入一个无休止的循环,并最终