执行HQL查询有两种方法,一种是list方法,另一种是iterate方法。这两种方法到底有什么区别,下面我们通过例子来说明两者的区别。

Company表:

wKioL1bVHaPArE8EAAAN7mNGBzQ433.png

Employee表(employee_company_id为外键)

wKioL1bVHaPDb5pwAAAbt64pCpc595.png

Company实体类:

import java.util.Set;

public class Company {
    private int companyId;
    private String companyName;
    private Set<Employee> companyEmployees;
    public int getCompanyId() {
        return companyId;
    }
    public void setCompanyId(int companyId) {
        this.companyId = companyId;
    }
    public String getCompanyName() {
        return companyName;
    }
    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }
    public Set<Employee> getCompanyEmployees() {
        return companyEmployees;
    }
    public void setCompanyEmployees(Set<Employee> companyEmployees) {
        this.companyEmployees = companyEmployees;
    }
}

Employee实体类:

public class Employee {
    private int employeeId;
    private String employeeName;
    private Company employeeCompany;
    public int getEmployeeId() {
        return employeeId;
    }
    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }
    public String getEmployeeName() {
        return employeeName;
    }
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
    public Company getEmployeeCompany() {
        return employeeCompany;
    }
    public void setEmployeeCompany(Company employeeCompany) {
        this.employeeCompany = employeeCompany;
    }
}

Company hbm配置:

<hibernate-mapping>
    <class name="com.jaeger.hibernatetest.day7.lazy.Company" table="company">
        <id name="companyId" column="company_id">
            <generator class="native"></generator>
     </id>

     <property name="companyName" column="company_name"/>
      <set name="companyEmployees" cascade="all">
           <key column="employee_company_id"></key>
        <one-to-many class="com.jaeger.hibernatetest.day7.lazy.Employee"/>
      </set>
   </class>
</hibernate-mapping>

Employee hbm配置:

<hibernate-mapping>
    <class name="com.jaeger.hibernatetest.day7.lazy.Employee" table="employee">
       <id name="employeeId" column="employee_id">
         <generator class="native"></generator>
     </id>

        <property name="employeeName" column="employee_name"/>
        <many-to-one name="employeeCompany" class="com.jaeger.hibernatetest.day7.lazy.Company" 
            foreign-key="fk_employee_company" column="employee_company_id"
            cascade="save-update">
        </many-to-one>
   </class>
</hibernate-mapping>

1. list方法
list方法会向数据库发出sql语句,一次查询出所有满足HQL语句的记录,测试方法如下:

List<Employee> allEmployees = session.createQuery("from Employee").list(); //A
for(Employee employee : allEmployees){
    System.out.println(employee.getEmployeeId());
    System.out.println(employee.getEmployeeName());
}

A:这里会发出sql去查询满足HQL条件的所有employee信息,sql如下:

select
     employee0_.employee_id as employee1_1_,
     employee0_.employee_name as employee2_1_,
     employee0_.employee_company_id as employee3_1_ 
  from
     employee employee0_

2. iterate方法

iterate方法只会查询表的主键返回的是Iterator对象,当我们真正使用对象时,才会用主键去数据库查找其他信息,测试方法如下:

Iterator<Employee> allEmployees = session.createQuery("from Employee").iterate(); //A
while(allEmployees.hasNext()){
    Employee employee = allEmployees.next();
    System.out.println(employee.getEmployeeId()); //B
    System.out.println(employee.getEmployeeName()); //C
}

A:这里会先去查询employee表的所有主键,sql如下:

select
     employee0_.employee_id as col_0_0_ 
  from
     employee employee0_

B:这里会返回employee id,但并不会向数据库发出sql语句,因为employee id为主键,上面已经查询出来了,使用不用在去数据库查询。

C:这里才会根据每个employee id再次去数据库查询其他信息。

select
     employee0_.employee_id as employee1_1_0_,
     employee0_.employee_name as employee2_1_0_,
     employee0_.employee_company_id as employee3_1_0_ 
  from
     employee employee0_ 
 where
     employee0_.employee_id=?

总结:
1. list方法只会查询一次,而iterate方法先会去查所有主键,再遍历主键去查询其他信息,所以总共会查询N+1次。当我们的程序要根据主键再来做不同处理的话,比如:if(employee.getEmployeeId() == 1),应该使用iterate,因为只取主键的话不会再发sql语句了,也会使加载数据大大减少。但如果要遍历所有信息的话,应该用list方法,可以一次加载所有信息,不用频繁的与数据库通信。
2. list方法查询实体对象返回的就是相应的对象,而iterate返回的则是相应对象的代理对象。
3. list和iterate在session缓存方面还有些区别,可以参考这篇文章:Hibernate一级缓存