[Java][JPA] JPA で大きなテーブルを走査する

JPA で行数の多いテーブルを select して getResultList() すると全部メモリに展開するので効率が良くないです。こういうとき、JDBC なら ResultSet をオープンしたままループしますし、S2JDBC なら iterate() 使いますね。ところが JPA には適切な方法がないようです。

こちらによれば、
http://stackoverflow.com/questions/5067619/jpa-what-is-the-proper-pattern-for-iterating-over-large-result-sets

プロダクト独自の方法を使えばいいようですが、pure JPA なベストアンサーの方法を Iterator でラップして使いやすくしてみました。

https://github.com/akr4/jpa-lazy-fetch-iterator

こんな感じで Iterable として返してやると便利でしょう。

public Iterable<Employee> getAllEmployees() {
    return new Iterable<Employee>() {
        @Override public Iterator<Employee> iterator() {
            return new LazyFetchIterator<Employee>(
                em,
                em.createQuery("select e from Employee e order by e.id", Employee.class),
                em.createQuery("select count(e) from Employee e", Long.class).getSingleResult(),
                1000);
        }
    };
}

第2引数の Query を使って 1000 件ずつフェッチします。

これくらいは JPA で提供してほしいなあ。