Я использую Payara 4.1 (Eclipselink 2.6), Postgres 9.6.
Я пытаюсь использовать ScrollableCursor для доступа к результатам данных, которые могут быть довольно большими. При тестировании мы получили ошибку java.lang.OutOfMemoryError при попытке выполнить запрос, поэтому я выполнил некоторые действия по устранению неполадок с дампом кучи с меньшим объемом данных и обнаружил, что org.postgresql.jdbc.PgResultSet занимает много памяти в строках ArrayList.
Основываясь на документации EclipseLink, вы просто предоставляете один подсказка для получения ScrollableCursor, но после присоединения исходного кода драйвера JDBC Postgres и отладки я обнаружил, что он будет загружать весь результат данных, если мы не установим размер выборки, поэтому я добавил QueryHints.JDBC_FETCH_SIZE. Однако я обнаружил, что он по-прежнему извлекает все результаты запроса и изначально сохраняет их в памяти.
В org.postgresql.v3.QueryExecutorImpl sendOneQuery устанавливает для начальных строк размер выборки только в том случае, если установлен флаг QUERY_FORWARD_CURSOR.
В org.postgresql.jdbc.PgStatement executeInternal он устанавливает флаг QUERY_FORWARD_CURSOR только в том случае, если есть размер выборки, набор результатов нельзя прокручивать, соединение не является автоматическим и набор результатов нельзя удерживать.
При отладке мое соединение настроено на автоматическую фиксацию, хотя я звоню из @TransactionAttribute(TransactionAttributeType.REQUIRED) в @Stateless ejb, вызываемом из другого метода @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) в другом @Stateless ejb.
Я не понимаю, почему в моем запросе используется новое соединение, по умолчанию настроенное на автоматическую фиксацию. Раньше я использовал 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();
}
}
}