概述
通过一个对象抓取关联对象需要发送 SQL ,SQL 如何发送及 SQL 的发送规则就可以通过抓取策略进行配置。
通过
<set>
或<many-to-one>
上的fetch
属性进行配置。
要考虑fetch
和这些标签上的lazy
如何配置才能最大化优化发送的 SQL 语句。
set 标签上的 fetch 和 lazy
fetch
指定抓取策略,控制 SQL 语句格式。
在这里 fetch
有三个可选值:
select
: 默认值,发送普通select
语句查询关联对象。join
:发送一条迫切左外连接查询关联对象。subselect
:发送子查询查询关联对象。
lazy
控制查询关联对象时是否使用懒加载。
在这里 lazy
有三个可选值:
true
:默认值,查询关联对象时,使用延迟加载。false
:查询关联对象时,不使用延迟加载。extra
:及其懒惰。
示例
例 1:fetch="select" lazy="true"
。
<!-- com/zze/bean/Class.hbm.xml -->
<!-- 默认值:-->
<set name="students" cascade="save-update" fetch="select" lazy="true">
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Class clazz = session.get(Class.class, 1);
for (Student student : clazz.getStudents()) {
System.out.println(student);// 发送 SQL
}
transaction.commit();
/*
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Hibernate:
select
students0_.cid as cid5_1_0_,
students0_.id as id1_1_0_,
students0_.id as id1_1_1_,
students0_.name as name2_1_1_,
students0_.age as age3_1_1_,
students0_.gender as gender4_1_1_,
students0_.cid as cid5_1_1_
from
student students0_
where
students0_.cid=?
Student{id=2, name='张三'}
Student{id=1, name='李四'}
*/
例 2:fetch="select" lazy="false"
。
<!-- com/zze/bean/Class.hbm.xml -->
<set name="students" cascade="save-update" fetch="select" lazy="false">
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Class clazz = session.get(Class.class, 1); //发送 2 条 SQL
for (Student student : clazz.getStudents()) {
System.out.println(student);
}
transaction.commit();
/*
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Hibernate:
select
students0_.cid as cid5_1_0_,
students0_.id as id1_1_0_,
students0_.id as id1_1_1_,
students0_.name as name2_1_1_,
students0_.age as age3_1_1_,
students0_.gender as gender4_1_1_,
students0_.cid as cid5_1_1_
from
student students0_
where
students0_.cid=?
Student{id=2, name='张三'}
Student{id=1, name='李四'}
*/
例 3:fetch="select" lazy="extra"
。
<!-- com/zze/bean/Class.hbm.xml -->
<set name="students" cascade="save-update" fetch="select" lazy="extra">
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Class clazz = session.get(Class.class, 1);
System.out.println(clazz.getStudents().size()); // 针对数量发送一条sql
transaction.commit();
/*
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Hibernate:
select
count(id)
from
student
where
cid =?
*/
例 4:fetch="join" lazy="true"
。
<!-- com/zze/bean/Class.hbm.xml -->
<!-- fetch="join" 时,lazy 失效 -->
<set name="students" cascade="save-update" fetch="join" lazy="true">
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Class clazz = session.get(Class.class, 1);// 发送 SQL
for (Student student : clazz.getStudents()) {
System.out.println(student);
}
transaction.commit();
/*
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_,
students1_.cid as cid5_1_1_,
students1_.id as id1_1_1_,
students1_.id as id1_1_2_,
students1_.name as name2_1_2_,
students1_.age as age3_1_2_,
students1_.gender as gender4_1_2_,
students1_.cid as cid5_1_2_
from
class class0_
left outer join
student students1_
on class0_.id=students1_.cid
where
class0_.id=?
Student{id=2, name='张三'}
Student{id=1, name='李四'}
*/
例 5:fetch="subselect" lazy="true"
。
<!-- com/zze/bean/Class.hbm.xml -->
<set name="students" cascade="save-update" fetch="subselect" lazy="true"> */
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("from Class");
List<Class> list = query.list();
for (Class clazz : list) {
Set<Student> students = clazz.getStudents(); // 发送 SQL
System.out.println(students);
}
transaction.commit();
/*
Hibernate:
select
class0_.id as id1_0_,
class0_.name as name2_0_
from
class class0_
Hibernate:
select
students0_.cid as cid5_1_1_,
students0_.id as id1_1_1_,
students0_.id as id1_1_0_,
students0_.name as name2_1_0_,
students0_.age as age3_1_0_,
students0_.gender as gender4_1_0_,
students0_.cid as cid5_1_0_
from
student students0_
where
students0_.cid in (
select
class0_.id
from
class class0_
)
[Student{id=1, name='李四'}, Student{id=2, name='张三'}]
[Student{id=4, name='赵六'}, Student{id=3, name='王五'}]
[Student{id=5, name='吴刚'}, Student{id=6, name='王如花'}]
[Student{id=7, name='李志静'}, Student{id=8, name='何王天'}]
*/
例 6:fetch="subselect" lazy="false"
。
<!-- com/zze/bean/Class.hbm.xml -->
<set name="students" cascade="save-update" fetch="subselect" lazy="false">
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("from Class");
List<Class> list = query.list(); // 发送 SQL
for (Class clazz : list) {
Set<Student> students = clazz.getStudents();
System.out.println(students);
}
transaction.commit();
/*
Hibernate:
select
class0_.id as id1_0_,
class0_.name as name2_0_
from
class class0_
Hibernate:
select
students0_.cid as cid5_1_1_,
students0_.id as id1_1_1_,
students0_.id as id1_1_0_,
students0_.name as name2_1_0_,
students0_.age as age3_1_0_,
students0_.gender as gender4_1_0_,
students0_.cid as cid5_1_0_
from
student students0_
where
students0_.cid in (
select
class0_.id
from
class class0_
)
[Student{id=1, name='李四'}, Student{id=2, name='张三'}]
[Student{id=4, name='赵六'}, Student{id=3, name='王五'}]
[Student{id=5, name='吴刚'}, Student{id=6, name='王如花'}]
[Student{id=7, name='李志静'}, Student{id=8, name='何王天'}]
*/
many-to-one 标签上的 fetch 和 lazy
fetch
指定抓取策略,控制 SQL 语句格式。
在这里 fetch
有两个可选值:
select
:默认值,发送普通的select
语句查询关联对象。join
:发送一条迫切左外连接查询关联对象。
lazy
控制查询关联对象时是否使用懒加载。
在这里 lazy
有三个可选值:
proxy
:默认值,引用关联对象类的类级别加载策略。flase
:查询关联对象时,不使用延迟加载。no-proxy
:不使用。
示例
例 1:fetch="select" lazy="proxy"
。
<!-- com/zze/bean/Student.hbm.xml -->
<!-- 默认值 -->
<many-to-one name="clazz" column="cid" class="com.zze.bean.Class" fetch="select" lazy="proxy"/>
<!-- com/zze/bean/Class.hbm.xml -->
<class name="com.zze.bean.Class" table="class" lazy="true">
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = session.get(Student.class, 1);
System.out.println(student.getClazz()); // 发送 SQL
transaction.commit();
/*
Hibernate:
select
student0_.id as id1_1_0_,
student0_.name as name2_1_0_,
student0_.age as age3_1_0_,
student0_.gender as gender4_1_0_,
student0_.cid as cid5_1_0_
from
student student0_
where
student0_.id=?
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Class{id=1, name='软件一班'}
*/
例 2:fetch="select" lazy="proxy"
。
<!-- com/zze/bean/Student.hbm.xml -->
<!-- 默认值 -->
<many-to-one name="clazz" column="cid" class="com.zze.bean.Class" fetch="select" lazy="proxy"/>
<!-- com/zze/bean/Class.hbm.xml -->
<class name="com.zze.bean.Class" table="class" lazy="false">
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = session.get(Student.class, 1);// 一次发送 2 条 SQL
System.out.println(student.getClazz());
transaction.commit();
/*
Hibernate:
select
student0_.id as id1_1_0_,
student0_.name as name2_1_0_,
student0_.age as age3_1_0_,
student0_.gender as gender4_1_0_,
student0_.cid as cid5_1_0_
from
student student0_
where
student0_.id=?
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Class{id=1, name='软件一班'}
*/
例 3:fetch="join" lazy="proxy"
。
<!-- com/zze/bean/Student.hbm.xml -->
<!-- fetch="join" 时,lazy 失效 -->
<many-to-one name="clazz" column="cid" class="com.zze.bean.Class" fetch="join" lazy="proxy"/>
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = session.get(Student.class, 1);// 一条关联 SQL
System.out.println(student.getClazz());
transaction.commit();
/*
Hibernate:
select
student0_.id as id1_1_0_,
student0_.name as name2_1_0_,
student0_.age as age3_1_0_,
student0_.gender as gender4_1_0_,
student0_.cid as cid5_1_0_,
class1_.id as id1_0_1_,
class1_.name as name2_0_1_
from
student student0_
left outer join
class class1_
on student0_.cid=class1_.id
where
student0_.id=?
Class{id=1, name='软件一班'}
*/
批量抓取
指的是一批指定数量的关联数据一起查询。
例 1:查询所有班级及对应班级下的学生信息。
默认情况:
// 默认情况下,查询所有班级会发一条 SQL,然后每次查询班级上的学生也会发送一条 SQL
// 即如下有 4 个班级,会发 5 条SQL
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("from Class");
List<Class> list = query.list();
for (Class clazz : list) {
System.out.println(clazz);
for (Student student : clazz.getStudents()) {
System.out.println(student);
}
}
transaction.commit();
/*
Hibernate:
select
class0_.id as id1_0_,
class0_.name as name2_0_
from
class class0_
Class{id=1, name='软件一班'}
Hibernate:
select
students0_.cid as cid5_1_0_,
students0_.id as id1_1_0_,
students0_.id as id1_1_1_,
students0_.name as name2_1_1_,
students0_.age as age3_1_1_,
students0_.gender as gender4_1_1_,
students0_.cid as cid5_1_1_
from
student students0_
where
students0_.cid=?
Student{id=1, name='李四'}
Student{id=2, name='张三'}
Class{id=2, name='软件二班'}
Hibernate:
select
students0_.cid as cid5_1_0_,
students0_.id as id1_1_0_,
students0_.id as id1_1_1_,
students0_.name as name2_1_1_,
students0_.age as age3_1_1_,
students0_.gender as gender4_1_1_,
students0_.cid as cid5_1_1_
from
student students0_
where
students0_.cid=?
Student{id=4, name='王五'}
Student{id=3, name='赵六'}
Class{id=3, name='汽修一班'}
Hibernate:
select
students0_.cid as cid5_1_0_,
students0_.id as id1_1_0_,
students0_.id as id1_1_1_,
students0_.name as name2_1_1_,
students0_.age as age3_1_1_,
students0_.gender as gender4_1_1_,
students0_.cid as cid5_1_1_
from
student students0_
where
students0_.cid=?
Student{id=5, name='王如花'}
Student{id=6, name='吴刚'}
Class{id=4, name='汽修二班'}
Hibernate:
select
students0_.cid as cid5_1_0_,
students0_.id as id1_1_0_,
students0_.id as id1_1_1_,
students0_.name as name2_1_1_,
students0_.age as age3_1_1_,
students0_.gender as gender4_1_1_,
students0_.cid as cid5_1_1_
from
student students0_
where
students0_.cid=?
Student{id=8, name='李志静'}
Student{id=7, name='何王天'}
*/
修改配置文件:
<!-- com/zze/bean/Class.hbm.xml -->
<set name="students" cascade="save-update" batch-size="4">
// 一次抓取 4 条,就只需要发送 2 次 SQL
// 一次查询所有班级,一次查询所有班级下的学生
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("from Class");
List<Class> list = query.list();
for (Class clazz : list) {
System.out.println(clazz);
for (Student student : clazz.getStudents()) {
System.out.println(student);
}
}
transaction.commit();
/*
Hibernate:
select
class0_.id as id1_0_,
class0_.name as name2_0_
from
class class0_
Class{id=1, name='软件一班'}
Hibernate:
select
students0_.cid as cid5_1_1_,
students0_.id as id1_1_1_,
students0_.id as id1_1_0_,
students0_.name as name2_1_0_,
students0_.age as age3_1_0_,
students0_.gender as gender4_1_0_,
students0_.cid as cid5_1_0_
from
student students0_
where
students0_.cid in (
?, ?, ?, ?
)
Student{id=1, name='李四'}
Student{id=2, name='张三'}
Class{id=2, name='软件二班'}
Student{id=4, name='王五'}
Student{id=3, name='赵六'}
Class{id=3, name='汽修一班'}
Student{id=5, name='王如花'}
Student{id=6, name='吴刚'}
Class{id=4, name='汽修二班'}
Student{id=7, name='何王天'}
Student{id=8, name='李志静'}
*/
例 2:查询所有学生及所有学生所属班级信息。
// 默认情况下,查询所有学生会发送 1 条 SQL,然后每次查询每个学生的所属班级时也会发送一条 SQL,
// 有 8 个学生,但一共有 4 个班级,由于一级缓存的作用,查询班级需要发送 4 条 SQL
// 共发 5 条 SQL
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("from Student");
List<Student> list = query.list();
for (Student student : list) {
System.out.println(student.getClazz());
}
transaction.commit();
/*
Hibernate:
select
student0_.id as id1_1_,
student0_.name as name2_1_,
student0_.age as age3_1_,
student0_.gender as gender4_1_,
student0_.cid as cid5_1_
from
student student0_
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Class{id=1, name='软件一班'}
Class{id=1, name='软件一班'}
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Class{id=2, name='软件二班'}
Class{id=2, name='软件二班'}
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Class{id=3, name='汽修一班'}
Class{id=3, name='汽修一班'}
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Class{id=4, name='汽修二班'}
Class{id=4, name='汽修二班'}
*/
修改配置文件:
<!-- com/zze/bean/Class.hbm.xml -->
<class name="com.zze.bean.Class" table="class" batch-size="3">
<!-- many-to-one 关系时需在关联属性类映射文件下配置 batch-size -->
// 查询所有学生 1 条 SQL,查询所有班级每次抓取 3 条,一共 4 个班级,会发 2 次 SQL
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("from Student");
List<Student> list = query.list();
for (Student student : list) {
System.out.println(student.getClazz());
}
transaction.commit();
/*
Hibernate:
select
student0_.id as id1_1_,
student0_.name as name2_1_,
student0_.age as age3_1_,
student0_.gender as gender4_1_,
student0_.cid as cid5_1_
from
student student0_
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id in (
?, ?, ?
)
Class{id=1, name='软件一班'}
Class{id=1, name='软件一班'}
Class{id=2, name='软件二班'}
Class{id=2, name='软件二班'}
Class{id=3, name='汽修一班'}
Class{id=3, name='汽修一班'}
Hibernate:
select
class0_.id as id1_0_0_,
class0_.name as name2_0_0_
from
class class0_
where
class0_.id=?
Class{id=4, name='汽修二班'}
Class{id=4, name='汽修二班'}
*/
评论区