Hibernate4Step6

hardwork

本着应用的目的快速学习Hibernate4框架

  • Hibernate检索策略

前面的话

本节主要介绍:

本节主要讲解Hibernate4的检索策略,主要包括如下:

  1. Lazy
  2. batch-size
  3. Fetch

检索策略属性Lazy

  • Lazy:true       (默认)延迟检索;   one-to-many 一对多

  • Lazy:false        延迟检索;               one-to-many 一对多

  • Lazy:extra       增强延迟检索;        one-to-many 一对多

  • Lazy:proxy    (默认)延迟检索;    many-to-one 多对一

  • Lazy:no-proxy 无代理延迟检索;     many-to-one 多对一

用一个Demo测试Lazy属性,Demo包括Student类和Class类,类图如下:

studentAndClass

Student.hbm.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.codeforgod.model">

<class name="Student" table="t_student">
<id name="id" column="studentId">
<generator class="native"></generator>
</id>

<property name="name" column="studentName"></property>

<many-to-one name="c" column="classId" class="cn.codeforgod.model.Class" cascade="save-update"></many-to-one>
</class>

</hibernate-mapping>

Class.hbm.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.codeforgod.model">

<class name="Class" table="t_class">
<id name="id" column="classId">
<generator class="native"></generator>
</id>

<property name="name" column="className"></property>

<set name="students" inverse="true">
<!-- 被参考的外键 -->
<key column="classId"></key>
<one-to-many class="cn.codeforgod.model.Student"/>
</set>
</class>

</hibernate-mapping>

数据库中表之间的关系如下:

studentAndClass

一、lazy=”true”

这是默认的方式,也可以在Class.hbm.xml显式配置如下:

1
2
3
4
5
<set name="students" inverse="true" lazy="true">
<!-- 被参考的外键 -->
<key column="classId"></key>
<one-to-many class="cn.codeforgod.model.Student"/>
</set>

JUnit测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void testLazy1()
{

/* 获取Class对象时,并不立即获取Class对象中的students,
* 当要使用到students时,Hibernate才会通过代理类去获取students
*/

Class c = (Class) session.get(Class.class, Long.valueOf(1));

Set<Student> studentList = (Set<Student>) c.getStudents();

// 当Hibernate检测到操作Class中的students时才会去获取Class中的students
// 这就是Hibernate的延迟检索策略
studentList.iterator();
}

二、lazy=”false”

在Class.hbm.xml配置如下:

1
2
3
4
5
<set name="students" inverse="true" lazy="false">
<!-- 被参考的外键 -->
<key column="classId"></key>
<one-to-many class="cn.codeforgod.model.Student"/>
</set>

JUnit测试:

1
2
3
4
5
6
7
8
9
10
@Test
public void testLazy2()
{

// 当配置了lazy="false"时,便会立即检索出Class中的students,
// 这一点可以通过Hibernate的SQL日志看出
Class c = (Class) session.get(Class.class, Long.valueOf(1));

// Set<Student> studentList = (Set<Student>) c.getStudents();
// studentList.iterator();
}

三、lazy=”extra”

当lazy=”true”时,执行如下语句:

1
2
3
4
5
6
7
8
@Test
public void testLazy3()
{

Class c = (Class) session.get(Class.class, Long.valueOf(1));
Set<Student> studentList = (Set<Student>) c.getStudents();
// 当只获取学生的数量时,Hibernate查询的是student所有信息
System.out.println(studentList.size());
}

生成的SQL如下:

Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=?

Hibernate: select students0_.classId as classId3_0_0_, students0_.studentId as studentI1_1_0_, students0_.studentId as studentI1_1_1_, students0_.studentName as studentN2_1_1_, students0_.classId as classId3_1_1_ from t_student students0_ where students0_.classId=?

当只需要查询students数量的时候,并没有对SQL进行优化,降低了效率和系统的性能。

此时配置lazy=”extra”时,执行以上语句的生成的SQL如下:

Hibernate: select count(studentId) from t_student where classId =?

Tips:虽然优化归优化了,但是在实际开发中使用的比较少,因为实际开发基本上不可能只获取数量,一般是要获取数据的。

四、lazy=”proxy”

在Student.hbm.xml配置如下:

1
2
<many-to-one name="c" column="classId" class="cn.codeforgod.model.Class"
cascade="save-update" lazy="proxy"></many-to-one>

JUnit测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void testLazy4()
{

/*
* 获取Student对象时,并不立即获取Student对象中的class,
* 当要使用到class时,Hibernate才会通过代理类去获取class
*/

Student student = (Student) session.get(Student.class, Long.valueOf(1));

// 当Hibernate检测到操作Student中的class时才会去数据库中获取Student中的class
// 这就是Hibernate的延迟检索策略
student.getC().getName();
}

代理类student中的c对象虽然不为空,但是也没有数据。

Tips:在实际开发中常用的属性有lazy="true"lazy="false",其它用的非常少。

五、lazy=”no-proxy”

此属性需要编译时字节码增强。

当执行完Student student = (Student) session.get(Student.class, Long.valueOf(1));时,student对象中的c为null,当执行student.getC().getName();时再去数据库中查询获取数据。

检索策略属性batch-size

  1. 批量延迟检索
  2. 批量立即检索

一、批量延迟检索

配置如下:

<set name="students" inverse="true" lazy="true" batch-size="3">
    <!-- 被参考的外键 -->
    <key column="classId"></key>
    <one-to-many class="cn.codeforgod.model.Student"/>
</set>

二、批量立即检索

配置如下:

<set name="students" inverse="true" lazy="false" batch-size="3">
    <!-- 被参考的外键 -->
    <key column="classId"></key>
    <one-to-many class="cn.codeforgod.model.Student"/>
</set>

检索策略属性Fetch

  1. Fetch:select(默认) 查询方式

  2. Fetch:subselect          子查询方式

  3. Fetch:join 迫切做外连接查询方式

一、Fetch:select(默认)

因为是默认的,所以不做说明了。

二、Fetch:subselect

配置如下:

<set name="students" inverse="true" lazy="false" batch-size="3"
    fetch="subselect">
    <!-- 被参考的外键 -->
    <key column="classId"></key>
    <one-to-many class="cn.codeforgod.model.Student" />
</set>

三、Fetch:join

配置如下:

<set name="students" inverse="true" lazy="false" batch-size="3"
    fetch="join">
    <!-- 被参考的外键 -->
    <key column="classId"></key>
    <one-to-many class="cn.codeforgod.model.Student" />
</set>

join一般用在get()方法中,所有的配置要视情况而定,调优性能。

坚持原创技术分享,您的支持将鼓励我继续创作