JPA/Hibernate似乎会将带有in子句的查询转换为多个带有=子句的查询。

5
我们实现了一种解决方案,以在合理的时间内收集大量重型对象且不会出现内存溢出问题(我说的是具有多个fetchType.eager关系的对象,这些对象本身又具有eager fetched关系的实体),首先选择这些对象的ids,然后基于这些ids选择对象本身。
在优化我们的代码时,我们发现(使用 hibernate.show_sql=true )我们用来收集这些对象的查询语句(select a from A a where a.id in:ids)被JPA / Hibernate转换为成千上万个查询语句,形式为select a from ...无尽的连接列表...where a.id =? 问题如下: 为什么JPA / Hibernate将我们初始的“in”子句查询转换为这么多的“=”子句查询。这不是低效的吗?如果是这样,是否有一种方法可以防止这种情况发生? 以下是我们代码调用查询的方式:
    Query q = this.getContext().createQuery("select a from A a where a.id in :ids");
    q.setParameter("ids", idList);
    return (List<A>) q.getResultList();

1
你使用的 Hibernate 版本是哪个? - Mạnh Quyết Nguyễn
hibernate_core 的版本是 5.2.12。 - Loïc Gammaitoni
https://dev59.com/zlTTa4cB1Zd3GeqPtpIS#5082504 - Syed Mehtab Hassan
3个回答

2

嗨,如果您想获取完整的实体对象,则应使用setParameterList而不是setParameter。 此外,在Hibernate中不需要使用select

最初的回答

 Query q = this.getContext().createQuery("from A a where a.id in (:ids)");
q.setParameterList("ids", idList);
return (List<A>) q.getResultList();

当我最初发布我的问题时,关于查询类型存在混淆。这是一个基本的JPA查询,因此应使用setParameter。感谢有关select的提示,我之前不知道。 - Loïc Gammaitoni

1
尽管我仍然无法解释为什么会对in子句中提供的每个ID生成一个查询(如我最初的问题所述),但我在这篇博客(https://thoughts-on-java.org/fetch-multiple-entities-id-hibernate/)上找到了解决此问题的方法。 解决方案是使用Hibernate的会话API,如下所示:
//get session object from entity manager
Session session = em.unwrap(Session.

MultiIdentifierLoadAccess<A> multiLoadAccess = session.byMultipleIds(A.class);
List<A> aObjects= multiLoadAccess.withBatchSize(1000).multiLoad(idList);
return aObjects;

0
如果您的idList超过1000个元素,您可能会遇到这个特定于Oracle的非最优化https://hibernate.atlassian.net/browse/HHH-9299
解决此问题的一种方法是将idList分成多个块,为每个块执行查询并连接结果。

我在执行查询之前考虑到了这个限制,并将我的ID列表分区。如果我的idList包含超过1000个元素,则会发生ORA异常。 - Loïc Gammaitoni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接