Queryのiterate()とscroll()

なんかよくわかっていなかったので、試してみた。

iterate()

テストコード
public void testIterator() throws Exception {
    Session session = getSession();
    Iterator<Employee> iterator =
        session.createQuery("from Employee e where e.id < 3").iterate();
    try {
        while (iterator.hasNext()) {
            Employee e = iterator.next();
            assertTrue(e instanceof HibernateProxy);
            assertTrue(session.contains(e));
            e.getEmployeeName();
        }
    } finally {
        Hibernate.close(iterator);
    }
}
実行されるSQL
Hibernate: 
    select
        employee0_.EMPLOYEE_ID as col_0_0_ 
    from
        Employee employee0_ 
    where
        employee0_.EMPLOYEE_ID<3
Hibernate: 
    select
        employee0_.EMPLOYEE_ID as EMPLOYEE1_2_0_,
        employee0_.EMPLOYEE_NO as EMPLOYEE2_2_0_,
        employee0_.EMPLOYEE_NAME as EMPLOYEE3_2_0_,
        employee0_.MANAGER_ID as MANAGER9_2_0_,
        employee0_.HIREDATE as HIREDATE2_0_,
        employee0_.SALARY as SALARY2_0_,
        employee0_.department_id as department8_2_0_,
        employee0_.ADDRESS_ID as ADDRESS7_2_0_,
        employee0_.VERSION as VERSION2_0_ 
    from
        Employee employee0_ 
    where
        employee0_.EMPLOYEE_ID=?
Hibernate: 
    select
        employee0_.EMPLOYEE_ID as EMPLOYEE1_2_0_,
        employee0_.EMPLOYEE_NO as EMPLOYEE2_2_0_,
        employee0_.EMPLOYEE_NAME as EMPLOYEE3_2_0_,
        employee0_.MANAGER_ID as MANAGER9_2_0_,
        employee0_.HIREDATE as HIREDATE2_0_,
        employee0_.SALARY as SALARY2_0_,
        employee0_.department_id as department8_2_0_,
        employee0_.ADDRESS_ID as ADDRESS7_2_0_,
        employee0_.VERSION as VERSION2_0_ 
    from
        Employee employee0_ 
    where
        employee0_.EMPLOYEE_ID=?
  • 最初にIDを取得するクエリを実行している。
  • クライアントにはプロキシを返す。
  • ID以外のプロパティにアクセスする段階で遅延ローディングされる。
    • 毎回プロパティにアクセスするとN+1回のSELECTが実行されることになる。
    • でも、すでにエンティティが永続コンテキストに入っていればSELECTは実行されない。
  • 永続コンテキストに格納される。
  • Iteratorの中で一番目のクエリのResultSetやPreparedStatementを持っているので自分でクローズしなきゃだめ。

scroll()

テストコード
public void testScroll() throws Exception {
    Session session = getSession();
    ScrollableResults results =
        session.createQuery("from Employee e where e.id < 3").scroll();
    try {
        while (results.next()) {
            Employee e = (Employee) results.get(0);
            assertFalse(e instanceof HibernateProxy);
            assertTrue(session.contains(e));
            e.getEmployeeName();
        }
    } finally {
        results.close();
    }
}
実行されるSQL
Hibernate: 
    select
        employee0_.EMPLOYEE_ID as EMPLOYEE1_2_,
        employee0_.EMPLOYEE_NO as EMPLOYEE2_2_,
        employee0_.EMPLOYEE_NAME as EMPLOYEE3_2_,
        employee0_.MANAGER_ID as MANAGER9_2_,
        employee0_.HIREDATE as HIREDATE2_,
        employee0_.SALARY as SALARY2_,
        employee0_.department_id as department8_2_,
        employee0_.ADDRESS_ID as ADDRESS7_2_,
        employee0_.VERSION as VERSION2_ 
    from
        Employee employee0_ 
    where
        employee0_.EMPLOYEE_ID<3
  • エンティティの全プロパティを取得するクエリが実行される。
  • クライアントに返すのはプロキシじゃない。
  • JDBCのスクロールの機能を使ってアクセスされる。
  • 永続コンテキストに格納される。
  • ScrollableResultsの中でResultSetやPreparedStatementを持っているので自分でクローズしなきゃだめ。