Java 带Postgres的Payara/EclipseLink中ScrollableCursor的内存问题
我使用的是Payara 4.1(Eclipselink 2.6),Postgres 9.6 我正在尝试使用ScrollableCursor访问可能非常大的数据结果。在测试中,我们在尝试运行查询时遇到了一个java.lang.OutOfMemory错误,因此我使用少量数据进行了一些heapdump故障排除,并在行ArrayList中发现org.postgresql.jdbc.PgResultSet占用了大量内存 基于此,您只需提供一个获取ScrollableCursor的提示,但在附加Postgres JDBC驱动程序源代码并进行调试后,我发现如果不设置获取大小,它将加载整个数据结果,因此我添加了QueryHints.JDBC_fetch_size。但我发现,它仍然在获取整个查询结果,并最初将它们保存到内存中 在org.postgresql.v3.QueryExecutorImpl sendOneQuery中,如果设置了查询向前光标标志,则仅将初始行设置为提取大小 在org.postgresql.jdbc.PgStatement executeInternal中,仅当存在提取大小、结果集不可滚动、连接不自动提交以及结果集不可保持时,才设置查询前进光标标记 调试时,我的连接被设置为自动提交,即使我是从@TransactionAttribute(TransactionAttributeType.REQUIRED)中的@TransactionAttribute(TransactionAttributeType.REQUIRED)方法调用@TransactionEJB中的@TransactionAttribute(TransactionAttributeType.Requireds)方法 我不明白为什么我的查询似乎使用了默认为自动提交的新连接。在我使用QueryHints.READ_之前,它是非事务性的,所以它可能使用了一个新的连接,但我删除了它。我的另一个查询提示是否导致新连接?是否有其他提示我应该使用?Payara/Eclipselink和Postgres是否存在错误,以至于在使用ScrollableCursor时它永远不会真正滚动Java 带Postgres的Payara/EclipseLink中ScrollableCursor的内存问题,java,postgresql,jpa,eclipselink,payara,Java,Postgresql,Jpa,Eclipselink,Payara,我使用的是Payara 4.1(Eclipselink 2.6),Postgres 9.6 我正在尝试使用ScrollableCursor访问可能非常大的数据结果。在测试中,我们在尝试运行查询时遇到了一个java.lang.OutOfMemory错误,因此我使用少量数据进行了一些heapdump故障排除,并在行ArrayList中发现org.postgresql.jdbc.PgResultSet占用了大量内存 基于此,您只需提供一个获取ScrollableCursor的提示,但在附加Postgr
private static <T> void executeScrollableQuery(@NotNull final Query query, final Consumer<T> recordConsumer) {
query.setHint(QueryHints.RESULT_SET_TYPE, ResultSetType.ForwardOnly)
.setHint(QueryHints.SCROLLABLE_CURSOR, HintValues.TRUE)
.setHint(QueryHints.MAINTAIN_CACHE, HintValues.FALSE).setHint(QueryHints.JDBC_FETCH_SIZE, 500);
ScrollableCursor cursor = null;
try {
cursor = (ScrollableCursor) query.getSingleResult();
while (cursor.hasNext()) {
recordConsumer.accept((T) cursor.next());
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
private static void executeScrollableQuery(@NotNull final Query Query,final Consumer recordConsumer){
query.setHint(QueryHints.RESULT\u SET\u TYPE,ResultSetType.ForwardOnly)
.setHint(QueryHints.SCROLLABLE_游标,hintValue.TRUE)
.setHint(QueryHints.MAINTAIN_CACHE,hintvalue.FALSE).setHint(QueryHints.JDBC_FETCH_SIZE,500);
ScrollableCursor=null;
试一试{
游标=(ScrollableCursor)query.getSingleResult();
while(cursor.hasNext()){
recordConsumer.accept((T)cursor.next());
}
}最后{
如果(光标!=null){
cursor.close();
}
}
}
据我所知,这是Postgres JDBC驱动程序的一个缺陷。作为一种解决方法,我能够在获取查询结果之前也传入实体管理器并在实体管理器上打开连接,这使得连接不会自动提交,因此它使用了提供的获取大小,并且没有在内存中获取整个查询结果
我认为这样做的原因是,打开连接会使事务变脏,然后游标使用写连接而不是新的自动提交读取连接进行读取
private static <T> void executeScrollableQuery(@NotNull final EntityManager em, @NotNull final Query query,
final Consumer<T> recordConsumer) {
query.setHint(QueryHints.RESULT_SET_TYPE, ResultSetType.ForwardOnly)
.setHint(QueryHints.SCROLLABLE_CURSOR, HintValues.TRUE)
.setHint(QueryHints.MAINTAIN_CACHE, HintValues.FALSE).setHint(QueryHints.JDBC_FETCH_SIZE, 500);
em.unwrap(Connection.class);
ScrollableCursor cursor = null;
try {
cursor = (ScrollableCursor) query.getSingleResult();
while (cursor.hasNext()) {
recordConsumer.accept((T) cursor.next());
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
private static void executeScrollableQuery(@NotNull final EntityManager em,@NotNull final Query Query,
最终消费者记录(消费者){
query.setHint(QueryHints.RESULT\u SET\u TYPE,ResultSetType.ForwardOnly)
.setHint(QueryHints.SCROLLABLE_游标,hintValue.TRUE)
.setHint(QueryHints.MAINTAIN_CACHE,hintvalue.FALSE).setHint(QueryHints.JDBC_FETCH_SIZE,500);
em.unwrap(Connection.class);
ScrollableCursor=null;
试一试{
游标=(ScrollableCursor)query.getSingleResult();
while(cursor.hasNext()){
recordConsumer.accept((T)cursor.next());
}
}最后{
如果(光标!=null){
cursor.close();
}
}
}
好的,根据我的猜测,postgres驱动程序可能按照预期工作,payara/eclipselink确实存在一个问题,它允许将自动提交连接与eclipselink.cursor.scrollable提示一起使用