저는 Payara 4.1 (Eclipselink 2.6), Postgres 9.6을 사용하고 있습니다.Postgres와 함께 Payara/EclipseLink의 ScrollableCursor에 메모리 문제가 발생했습니다.
ScrollableCursor를 사용하여 매우 큰 데이터 결과에 액세스하려고합니다. 테스트에서 java.lang.OutOfMemoryError를 실행하여 쿼리를 실행하려고 했으므로 적은 양의 데이터로 힙 덤프 문제 해결을 수행하고 ArrayList 행의 org.postgresql.jdbc.PgResultSet에서 많은 메모리를 차지했습니다.
EclipseLink documentation을 기반으로하면 ScrollableCursor를 얻는 한 가지 힌트 만 제공하지만 Postgres JDBC 드라이버 소스 코드를 첨부하고 디버깅을 한 후에 가져온 크기를 설정하지 않으면 전체 데이터 결과를로드하는 것으로 나타났습니다. 그래서 QueryHints.JDBC_FETCH_SIZE를 추가했습니다. 그래도 나는 전체 쿼리 결과를 가져 와서 처음에 메모리에 저장한다는 것을 알게되었습니다.
org.postgresql.v3.QueryExecutorImpl sendOneQuery에서는 QUERY_FORWARD_CURSOR 플래그가 설정된 경우에만 초기 행을 반입 크기로 설정합니다.
org.postgresql.jdbc.PgStatement executeInternal 가져 오기 크기가 있고 결과 집합을 스크롤 할 수 없으며 연결이 autoCommit가 아니며 결과 집합을 보유 할 수없는 경우에만 QUERY_FORWARD_CURSOR flage를 설정합니다.
다른 @Stateless ejb의 다른 @TransactionAttribute (TransactionAttributeType.REQUIRES_NEW) 메소드에서 호출 된 @Stateless ejb에서 @TransactionAttribute (TransactionAttributeType.REQUIRED)에서 호출하더라도 내 연결을 디버깅 할 때 자동 커밋으로 설정됩니다.
내 쿼리가 자동 연결을 기본값으로 사용하는 새로운 연결을 사용하는 것으로 보이는 이유가 표시되지 않습니다. QueryHints.READ_ONLY를 사용하기 전에는 트랜잭션이 아니므로 새 연결을 사용하고있을 가능성이 있지만이를 제거했습니다. 내 다른 쿼리 힌트 중 하나가 새로운 연결을 야기하고 있습니까? 내가 사용해야 할 힌트가 있습니까? Payara/Eclipselink와 Postgres에 버그가있어서 ScrollableCursor를 사용할 때 실제로 스크롤되지 않습니다.
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();
}
}
}