概述
我正在尝试使用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)
答案 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循环,为每个这样的批处理执行单独的查询并收集结果。