2017-11-15 25 views
1

私は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)メソッドから呼び出されたEJB @Statelessに@TransactionAttribute(TransactionAttributeType.REQUIRED)から呼んでいるにもかかわらず、自動コミットするように設定されています。

私のクエリが自動接続にデフォルトの新しい接続を使用しているように見える理由はわかりません。 QueryHints.READ_ONLYを使用する前は非トランザクションなので、おそらく新しい接続を使用していましたが、削除しました。他のクエリのヒントの1つが新しい接続を引き起こしていますか?私が使用すべき追加のヒントはありますか? 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(); 
     } 
    } 
} 

答えて

0

私の知る限り、Postgres JDBCドライバのバグです。この問題を回避するには、エンティティマネージャを渡すことができ、クエリ結果を取得する前にエンティティマネージャの接続をアンラップして、接続が自動コミットされないようにして、指定されたフェッチサイズを使用してクエリ全体メモリが得られます。

私は、接続をアンラッピングするとトランザクションが汚くなり、新しい自動コミット読み取り接続の代わりに書き込み接続を使用してカーソルが読み取られることが考えられます。私が意図したとおりにPostgresのドライバが動作することができると思いますし、それは実際にeclipselink.cursor.scrollableで使用する自動コミットの接続が可能だということペーシュ・カショーロ/ EclipseLinkを持つ問題だthis documentationに基づいて

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(); 
     } 
    } 
} 

[OK]を、ヒント。