一尘不染

JPA:对大型结果集进行迭代的正确模式是什么?

hibernate

假设我有一个包含数百万行的表。使用JPA,迭代对该表的查询的正确方法是什么,以至于 我没有一个 包含数百万个对象 的内存列表

例如,如果表很大,我怀疑以下内容会爆炸:

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

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

分页(循环和手动更新setFirstResult()/ setMaxResult())真的是最好的解决方案吗?

编辑
:我针对的主要用例是一种批处理作业。如果需要很长时间才能运行就可以了。没有涉及Web客户端。我只需要为每一行“做某事”,一次一行(或一些小N)。我只是想避免将它们全部同时存储在内存中。


阅读 271

收藏
2020-06-20

共1个答案

一尘不染

Java Persistence with Hibernate的第537页提供了一个使用的解决方案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();
    }
}
2020-06-20