mysql hql fetch_Hibernate fetch 抓取策略

上一篇文章(Hibernate的延迟加载 ,懒加载,lazy)说到Hibernate的延迟加载跟fetch的配置还有一定关系,下面就来讨论下fetch的用法。

抓取策略(fetch)是指当我们去查询一个对象里面所关联的其他对象时,按照哪种方法去抓取关联对象。

fetch策略常用的有三种:select、subselect、join,下面我们一一介绍。我们还是用上面介绍延迟加载的相关表和实体类。

Company表:

8bb06b3d1944a0f718bdc748fa58d250.png

Employee表(employee_company_id为外键)

a19092c4ce3ebbdcadcf8c5178977120.png

Company实体类:import java.util.Set;

public class Company {

private int companyId;

private String companyName;

private Set 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 getCompanyEmployees() {

return companyEmployees;

}

public void setCompanyEmployees(Set 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配置:

Employee hbm配置:

foreign-key="fk_employee_company" column="employee_company_id"

cascade="save-update">

fetch属性用在、、、等关联标签里,我们就用来介绍,但subselect策略只能用于和。从数据库取数据就用get()方法,让外层对象不用延迟加载。

1. select

作用:查询关联对象时,是拿外层对象的外键,向数据库再发送select语句去抓取关联对象。

修改上面Employee hbm的配置:

foreign-key="fk_employee_company" column="employee_company_id"

cascade="save-update" fetch="select">

在标签中我们添加了fetch="select",下面是测试代码:Employee employee = (Employee)session.get(Employee.class, 1); //A

System.out.println(employee.getEmployeeName());

Company company = employee.getEmployeeCompany(); //B

System.out.println(company.getCompanyName()); //C

A:此处会生成sql语句去查询employee的信息。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=?

B:此处不会马上去取company的信息,因为里面默认是lazy="proxy"支持懒加载的。

C:此处会根据employee的外键去查找company的信息,用的就是select fetch策略。select

company0_.company_id as company_1_0_0_,

company0_.company_name as company_2_0_0_

from

company company0_

where

company0_.company_id=?

注意:等关联标签默认是fetch="select"的,所以我们不配置也会采用多条select语句的方式去查询关联对象。

2. join

作用:查询关联对象时,是拿外层对象的外键去join关联对象的表,把关联对象一起取出来。

修改上面Employee hbm的配置:

foreign-key="fk_employee_company" column="employee_company_id" cascade="save-update" fetch="join">

在标签中我们换成了fetch="join",下面是测试代码:Employee employee = (Employee)session.get(Employee.class, 1); //A

System.out.println(employee.getEmployeeName());

Company company = employee.getEmployeeCompany(); //B

System.out.println(company.getCompanyName()); //C

A:此处会生成sql语句去查询employee的信息,并用left join去查询company的信息。select

employee0_.employee_id as employee1_1_0_,

employee0_.employee_name as employee2_1_0_,

employee0_.employee_company_id as employee3_1_0_,

company1_.company_id as company_1_0_1_,

company1_.company_name as company_2_0_1_

from

employee employee0_

left outer join

company company1_

on

employee0_.employee_company_id=company1_.company_id

where

employee0_.employee_id=?

B、C:这两处都不会再生成sql去数据库查询了,因为上面已经通过join拿到了company的信息。

所以使用join策略的话,关联对象的延迟加载就没用了,因为第一个select语句就已经join查询出了关联对象的信息。

3. subselect

作用:

subselect策略只能用于和,所以用来说明。

我们先来看看在默认的select策略下的执行过程。测试代码如下:List allCompany = session.createCriteria(Company.class).list(); //A

for(Company company : allCompany){

for(Employee employee : company.getCompanyEmployees()){ //B

System.out.println(employee.getEmployeeName());

}

}

A:发出查询sql语句去查询所有的company信息select

this_.company_id as company_1_0_0_,

this_.company_name as company_2_0_0_

from

company this_

B:这里会根据company_id去查询关联的employee信息select

companyemp0_.employee_company_id as employee3_0_0_,

companyemp0_.employee_id as employee1_1_0_,

companyemp0_.employee_id as employee1_1_1_,

companyemp0_.employee_name as employee2_1_1_,

companyemp0_.employee_company_id as employee3_1_1_

from

employee companyemp0_

where

companyemp0_.employee_company_id=?

上面的sql会重复向数据库发送N次,有多少个company就发送多少次。如果有很多不同的company,这种方式肯定是不合适的,因为会向数据库发送很多重复的sql语句。

下面我们来看看subselect策略,先修改Company hbm配置:

测试代码跟上面一样:List allCompany = session.createCriteria(Company.class).list(); //A

for(Company company : allCompany){

for(Employee employee : company.getCompanyEmployees()){ //B

System.out.println(employee.getEmployeeName());

}

}

A:发出查询sql语句去查询所有的company信息select

this_.company_id as company_1_0_0_,

this_.company_name as company_2_0_0_

from

company this_

B:这里会用一个select子查询去查询所有的employee信息select

companyemp0_.employee_company_id as employee3_0_1_,

companyemp0_.employee_id as employee1_1_1_,

companyemp0_.employee_id as employee1_1_0_,

companyemp0_.employee_name as employee2_1_0_,

companyemp0_.employee_company_id as employee3_1_0_

from

employee companyemp0_

where

companyemp0_.employee_company_id in (

select

this_.company_id

from

company this_

)

上面的sql只会向数据库发一次,因为所有的employee都已经取出来了。

对于对于set来说,如果用于遍历,则使用subselect,这样可以一次性把所有数据取出来;如果只取set里几条数据就用默认的select,这样虽然会发送多次sql,但查询量较少。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值