来自OpenJPA CriteriaQuery的java.lang.StackOverflowError使用大型查询

时间:2013-06-30 01:35:56

标签: derby openjpa

概述

我正在尝试使用OpenJPA CriteriaQuery来计算数据库表中满足某些属性的对象数。

我需要能够应用过滤器 - 只有在已知ID列表中有ID时,才能计算满足特定属性的对象数。

如果列表非常大,我无法执行此操作。

详细说明

我正在使用OpenJPA 2.2.1和底层的Derby DB。

我的CriteriaQuery被映射到一个带有WHERE子句的SQL查询 t1.qid = ? OR t1.qid = ? OR t1.qid = ? ... 对于每个已知ID。

这通常很好。

如果此列表变大(例如列表中的一千个或更多ID),则会因java.lang.StackOverflowError而失败。

问题

  • 是否有更好的方法来应用可扩展到任何过滤器的过滤器 任意数量的对象ID?

  • 有没有办法避免这个错误?

我在下面提供了我的代码的简化版本,以及导致的OpenJPA异常和derby.log错误。


我的代码的简化版本:

Collection<Integer> qids = A_LARGE_SET_OF_INTEGERS;

// prepare a criteria query to count objects that match some parameters
CriteriaQuery<Long> criteria = builder.createQuery(Long.class);
Root<MyObjectType> myrootobj = criteria.from(MyObjectType.class);

// counting the number of qids - a nonunique ID value in MyObjectType
criteria.select(builder.countDistinct(myrootobj.get(MyObjectType_.qid)));

// prepare a filter based on a property of the object
Predicate someProperty = builder.equal(myrootobj.get(MyObjectType_.someattr).get(MyOtherObjectType_.id), somefilterid);

// prepare a filter to limit to objects with an ID in the provided set
Predicate filteredObjects = myrootobj.get(MyObjectType_.qid).in(qids);

// apply the filter
criteria.where(builder.and(someProperty, filteredObjects));

long count = em.createQuery(criteria).getSingleResult();

我能看到的唯一SQL异常错误是SQLState:XJ001错误代码:-1

抛出的异常如下所示:

  <openjpa-2.2.1-r422266:1396819 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Failed to execute query "null". Check the query syntax for correctness. See nested exception for details.
    at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:872)
    at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:794)
    at org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.java:542)
    at org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:286)
    at org.apache.openjpa.persistence.QueryImpl.getResultList(QueryImpl.java:302)
    at org.apache.openjpa.persistence.QueryImpl.getSingleResult(QueryImpl.java:330)
    at my.code.that.uses.CriteriaQuery
    at sun.reflect.GeneratedMethodAccessor335.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
    at java.lang.reflect.Method.invoke(Method.java:613)
    at ...
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: DERBY SQL error: SQLCODE: -1, SQLSTATE: XJ001, SQLERRMC: java.lang.StackOverflowErrorXJ001.U {SELECT COUNT(DISTINCT t1.id) FROM SomeObjectType t0 INNER JOIN Something t1 ON t0.SOMETHING_ID = t1.id WHERE (t0.attr = ? AND t1.RUN_ID = ? AND (t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ?) AND t1.qid IS NOT NULL)} [code=-1, state=XJ001]
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:219)
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:199)
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.access$000(LoggingConnectionDecorator.java:59)
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection.prepareStatement(LoggingConnectionDecorator.java:251)
    at org.apache.openjpa.lib.jdbc.DelegatingConnection.prepareStatement(DelegatingConnection.java:133)
    at org.apache.openjpa.lib.jdbc.ConfiguringConnectionDecorator$ConfiguringConnection.prepareStatement(ConfiguringConnectionDecorator.java:140)
    at org.apache.openjpa.lib.jdbc.DelegatingConnection.prepareStatement(DelegatingConnection.java:133)
    at org.apache.openjpa.jdbc.kernel.JDBCStoreManager$RefCountConnection.prepareStatement(JDBCStoreManager.java:1646)
    at org.apache.openjpa.lib.jdbc.DelegatingConnection.prepareStatement(DelegatingConnection.java:122)
    at org.apache.openjpa.jdbc.sql.SQLBuffer.prepareStatement(SQLBuffer.java:449)
    at org.apache.openjpa.jdbc.sql.SQLBuffer.prepareStatement(SQLBuffer.java:429)
    at org.apache.openjpa.jdbc.sql.SelectImpl.prepareStatement(SelectImpl.java:479)
    at org.apache.openjpa.jdbc.sql.SelectImpl.execute(SelectImpl.java:420)
    at org.apache.openjpa.jdbc.sql.SelectImpl.execute(SelectImpl.java:391)
    at org.apache.openjpa.jdbc.sql.LogicalUnion$UnionSelect.execute(LogicalUnion.java:427)
    at org.apache.openjpa.jdbc.sql.LogicalUnion.execute(LogicalUnion.java:230)
    at org.apache.openjpa.jdbc.sql.LogicalUnion.execute(LogicalUnion.java:220)
    at org.apache.openjpa.jdbc.kernel.SelectResultObjectProvider.open(SelectResultObjectProvider.java:94)
    at org.apache.openjpa.kernel.QueryImpl$PackingResultObjectProvider.open(QueryImpl.java:2070)
    at org.apache.openjpa.kernel.QueryImpl.singleResult(QueryImpl.java:1320)
    at org.apache.openjpa.kernel.QueryImpl.toResult(QueryImpl.java:1242)
    at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:1007)
    at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:863)
    ... 75 more

请注意,我已经在ReportingSQLException中剪断了SQL查询,因为它很长 - 我删除了数百个OR t1.qid = ?子句。有超过一千个。


derby.log包含以下内容:

2013-06-30 01:03:16.279 GMT Thread[DRDAConnThread_36,5,main] (XID = 11562784), (SESSIONID = 23), (DATABASE = /full/path/to/my/db), (DRDAID = NF000001.CE86-507216535478407432{22}), Failed Statement is: SELECT COUNT(DISTINCT t1.id) FROM SomeObjectType t0 INNER JOIN Something t1 ON t0.SOMETHING_ID = t1.id WHERE (t0.attr = ? AND t1.RUN_ID = ? AND (t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ? OR t1.qid = ?) AND t1.qid IS NOT NULL)
java.lang.StackOverflowError
    at org.apache.derby.impl.sql.compile.OrNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.OrNode.changeToCNF(Unknown Source)
    <snip - over a thousand more lines like these>
    at org.apache.derby.impl.sql.compile.OrNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.OrNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.OrNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.OrNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.OrNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.AndNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.AndNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.AndNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.AndNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.AndNode.changeToCNF(Unknown Source)
    at org.apache.derby.impl.sql.compile.SelectNode.normExpressions(Unknown Source)
    at org.apache.derby.impl.sql.compile.SelectNode.preprocess(Unknown Source)
    at org.apache.derby.impl.sql.compile.DMLStatementNode.optimizeStatement(Unknown Source)
    at org.apache.derby.impl.sql.compile.CursorNode.optimizeStatement(Unknown Source)
    at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown Source)
    at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source)
    at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement.<init>(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement20.<init>(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement30.<init>(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement40.<init>(Unknown Source)
    at org.apache.derby.jdbc.Driver40.newEmbedPreparedStatement(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedConnection.prepareStatement(Unknown Source)
    at org.apache.derby.impl.drda.DRDAStatement.prepare(Unknown Source)
    at org.apache.derby.impl.drda.DRDAStatement.explicitPrepare(Unknown Source)
    at org.apache.derby.impl.drda.DRDAConnThread.parsePRPSQLSTT(Unknown Source)
    at org.apache.derby.impl.drda.DRDAConnThread.processCommands(Unknown Source)
    at org.apache.derby.impl.drda.DRDAConnThread.run(Unknown Source)

2 个答案:

答案 0 :(得分:3)

我相信这是DERBY-3876:https://issues.apache.org/jira/browse/DERBY-3876

解决方法是使用JVM设置线程堆栈大小的能力。例如, 如果您的Java版本接受该标志,请尝试-Xss = 2048k。

答案 1 :(得分:0)

使用OpenJPA和MS SQL Server我在一个很长的id列表中遇到了类似的问题,但是在OrExpression.initialize中。由Bryan Pendleton给出的堆栈大小的技巧解决了OpenJPA方面的问题。

但是现在我正在达到sql server的2100参数限制。

(可能取决于查询)一种解决方案是将id的集合分成例如1000.创建一个for循环,为每个这样的批处理执行单独的查询并收集结果。