0

概述

我正在尝试使用 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)
4

2 回答 2

3

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

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

于 2013-07-02T01:52:30.600 回答
0

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

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

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

于 2014-06-27T15:19:58.140 回答