有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

为了在合理的时间内收集大量重对象而不造成内存溢出(我指的是具有多个fetchType.eager关系的对象,对于本身具有eager fetched关系的实体),我们实现的一个解决方案是首先选择这些对象的ID,然后根据这些ID选择对象本身

到了优化代码的时候,我们注意到(使用hibernate.show_sql=true),我们用来收集这些对象的查询(select a from A a where a.id in :ids)被JPA/Hibernate翻译成数千个形式为select a from ...endless join list... 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();

共 (3) 个答案

  1. # 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;
    
  2. # 2 楼答案

    如果您的idList超过1000个元素,您可能会遇到这个特定于Oracle的去优化https://hibernate.atlassian.net/browse/HHH-9299

    解决这个问题的一种方法是将idList分成多个块,对每个块执行一个查询,并连接结果

  3. # 3 楼答案

    您好,您应该使用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();