JPA: 大きな結果セットを反復処理するための適切なパターンは何ですか? 質問する

JPA: 大きな結果セットを反復処理するための適切なパターンは何ですか? 質問する

数百万行のテーブルがあるとします。JPAを使用して、そのテーブルに対してクエリを反復処理する適切な方法は何でしょうか。メモリ内のリストがすべて揃っていない何百万ものオブジェクトがありますか?

たとえば、テーブルが大きい場合、次のコードが失敗すると思われます。

List<Model> models = entityManager().createQuery("from Model m", Model.class).getResultList();

for (Model model : models)
{
     System.out.println(model.getId());
}

ページネーション (ループしてsetFirstResult()/を手動で更新するsetMaxResult()) は本当に最善の解決策でしょうか?

編集: 私がターゲットとしている主なユースケースは、一種のバッチ ジョブです。実行に長い時間がかかっても問題ありません。Web クライアントは関係ありません。行ごとに 1 つ (または小さな N 個) ずつ「何か」を実行する必要があります。同時にすべての行がメモリ内に保持されることを避けたいだけです。

ベストアンサー1

537ページ目Hibernate を使用した Java Persistenceを使用したソリューションが提供されていますScrollableResultsが、残念ながらそれは Hibernate 専用です。

setFirstResultしたがって、 /と手動の反復処理の使用が本当に必要であると思われますsetMaxResults。これが JPA を使用した私の解決策です:

private List<Model> getAllModelsIterable(int offset, int max)
{
    return entityManager.createQuery("from Model m", Model.class).setFirstResult(offset).setMaxResults(max).getResultList();
}

次のように使用します。

private void iterateAll()
{
    int offset = 0;

    List<Model> models;
    while ((models = Model.getAllModelsIterable(offset, 100)).size() > 0)
    {
        entityManager.getTransaction().begin();
        for (Model model : models)
        {
            log.info("do something with model: " + model.getId());
        }

        entityManager.flush();
        entityManager.clear();
        em.getTransaction().commit();
        offset += models.size();
    }
}

おすすめ記事