【问题标题】:Stackoverflow with Hibernate using sql IN (id, id, id, id..id)Stackoverflow 与 Hibernate 使用 sql IN (id, id, id, id..id)
【发布时间】:2014-10-08 05:19:21
【问题描述】:

我收到下面的错误,说有堆栈溢出。发生这种情况是因为带有 IN (id, id, id...id) 的 sql 语句有大量参数。有没有什么办法解决这一问题?这发生在我使用 Eclipse 的本地环境中。

JPA

@Query(value="SELECT p FROM PendingCourseRegistration p WHERE p.sisId IN ?1 AND p.testId = ?2")
List<PendingCourseRegistration> findPendingCourseRegistrationInSisIdsAndTestId(List<String> sisIds, Long testID);

错误

java.lang.StackOverflowError: null
    at java.lang.Abstract witingBuilder.append(AbstractStringBuilder.java:416) ~[na:1.7.0_17]
    at java.lang.StringBuffer.append(StringBuffer.java:237) ~[na:1.7.0_17]
    at antlr.BaseAST.toStringList(BaseAST.java:341) ~[antlr-2.7.7.jar:na]
    at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:na]
    at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:na]
    at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:na]

休眠查询

2:26.763 [ocPifScheduler-1] DEBUG o.s.o.j.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation
09:52:26.788 [Scheduler-1] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - parse() - HQL: SELECT p FROM com.test.PendingCourseRegistration p WHERE p.sisId IN (:x10_, :x11_, :x12_, :x13_, :x14_, :x15_, :x16_, :x17_, :x18_, :x19_, :x110_, :x111_, :x112_, :x113_, :x114_, :x115_, :x116_, :x117_, :x118_, :x119_, ...:xN) AND p.id = ?2
09:52:26.891 [Scheduler-1] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - --- HQL AST ---
 \-[QUERY] Node: 'query'
    +-[SELECT_FROM] Node: 'SELECT_FROM'
    |  +-[FROM] Node: 'FROM'
    |  |  \-[RANGE] Node: 'RANGE'
    |  |     +-[DOT] Node: '.'
    |  |     |  +-[DOT] Node: '.'
    |  |     |  |  +-[DOT] Node: '.'
    |  |     |  |  |  +-[DOT] Node: '.'
    |  |     |  |  |  |  +-[DOT] Node: '.'
    |  |     |  |  |  |  |  +-[DOT] Node: '.'
    |  |     |  |  |  |  |  |  +-[IDENT] Node: 'com'
    |  |     |  |  \-[IDENT] Node: 'model'
    |  |     |  \-[IDENT] Node: 'PendingCourseRegistration'
    |  |     \-[ALIAS] Node: 'p'
    |  \-[SELECT] Node: 'SELECT'
    |     \-[IDENT] Node: 'p'
    \-[WHERE] Node: 'WHERE'
       \-[AND] Node: 'AND'
          +-[IN] Node: 'in'
          |  +-[DOT] Node: '.'
          |  |  +-[IDENT] Node: 'p'
          |  |  \-[IDENT] Node: 'sisId'
          |  \-[IN_LIST] Node: 'inList'
          |     +-[COLON] Node: ':'
          |     |  \-[IDENT] Node: 'x10_'
          |     +-[COLON] Node: ':'
          |     |  \-[IDENT] Node: 'x11_'
          |     +-[COLON] Node: ':'
          |     |  \-[IDENT] Node: 'x12_'
          |     +-[COLON] Node: ':'
          |     |  \-[IDENT] Node: 'x13_'
          |     +-[COLON] Node: ':'
          |     |  \-[IDENT] Node: 'x14_'
          |     +-[COLON] Node: ':'
          |     |  \-[IDENT] Node: 'x15_'
          |     +-[COLON] Node: ':'
          |     |  \-[IDENT] Node: 'x16_'
          |     +-[COLON] Node: ':'
          |     |  \-[IDENT] Node: 'x17_'

【问题讨论】:

  • 你有哪个版本的hibernate?
  • 4.1.12.Final 是我们正在使用的版本。

标签: java mysql sql hibernate stack-overflow


【解决方案1】:

我无法使用 Hibernate 4.2.4 复制它 您能否提供您正在使用的 Hibernate 版本? 我建议的另一件事是在执行方法时尝试在“antlr.BaseAST.toStringList()”上放置一个断点,并查看运行时变量和调用 antlr 方法并导致循环的方法

希望对你有帮助

【讨论】:

  • 发生在带有 JDK 8 的 Hibernate 4.3.6 中,列表中有 5000 个条目。我正在使用 CriteriaQuery: CriteriaBuilder builder = getEntityManager().getCriteriaBuilder(); CriteriaQuery cq = builder.createQuery(getEntityClass()); Root root = cq.from(getEntityClass()); cq.select(root).where(root.get(getIdProperty()).in(ids)); TypedQuery 查询 = getEntityManager().createQuery(cq); return query.getResultList();
【解决方案2】:

在我们使用 Hibernate 4.3.1.Final 的 Grails 项目 (2.3.6) 中,我们从未遇到过该错误,但由于查询缓冲区大小限制,我们遇到了另一个错误:

由于您使用的是in (?, ..., ?),因此您编写的?, 与列表中的项目一样多,这意味着对于大列表(例如 50000),您可能会编写 100000 个字符的查询,并且您可能会遇到此异常(这里使用 pgSQL 驱动程序):

Foobar.executeQuery("select f from Foobar f where f.id in (:ids)", 
                 [ids: 1L..100000L]); // Groovy way of creating a list of 100000 items.

还有错误:

SqlExceptionHelper:146 - An I/O error occured while sending to the backend. 
SqlExceptionHelper:146 - This connection has been closed.

这就是我认为你可能需要这样做的原因

  1. 要么将您的 id 列表拆分为较小的列表(如 500 条左右),然后手动合并结果,这比您使用的默认 spring-data 要做的工作更多。

    李>
  2. 要么将 id 列表存储到临时表中(这可能证明使用 JPA 是一项痛苦的任务)。临时表将是 (key, sids) 的元组。您将生成一个临时密钥(用于会话),使用密钥将 ID 批量插入到该表中,刷新以便休眠将更改推送到数据库,使用子查询(p.sidIds in (select sisIds from IdTable where key = ?1))使用该表,从中删除数据桌子。 虽然是一项痛苦的任务,但它可能会提高性能。

【讨论】:

  • 我基本上只是为每个实体做了多次调用。这不是一个高流量的网站,所以没什么大不了的。可能将其分块或转到其他版本可能会起作用,但我没有时间这样做。
  • 好吧,如果你有番石榴,你可能会做一些很好的事情,并且有工具来拆分你的列表并调用你的方法。在更新 Hibernate 时,我可以理解,虽然不这样做:最后一个是 4.3.6.Final。在发布之前,您可能需要重新检查整个应用程序。
猜你喜欢
  • 2018-11-14
  • 2015-11-06
  • 1970-01-01
  • 2014-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-05
  • 1970-01-01
相关资源
最近更新 更多