4.0、Hibernate-延迟加载 2
消费者 和 订单 属于 一对多 的 关系,通过上一章节 3.0 的内容我们知道了可以通过设置 customer 来实现延迟加载,本章节来介绍一下如何设置 orders 去实现延迟加载;
one-to-many 的 lazy 默认是 true 是开启的,先比较之下 many-to-one 默认是 false 是关闭的;
第一步:将order.hbm.xml 文件中改为 lazy = false,customer.hbm.xml 不变仍旧是 lazy = extra ->
<many-to-one name="customer" class="com.hkl.pojo.Customer" column="cid" lazy="false"></many-to-one>
第二步:创建 Test5.java 测试文件,如下所示 ->
import com.hkl.pojo.Order;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test5 {
public static void main(String[] args) {
// 创建configuration
Configuration configuration = new Configuration().configure();
// 获取sessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
// 获取Session
Session session = sessionFactory.openSession();
Order order = session.get(Order.class,3);
System.out.println(order);
session.close();
}
}
第三步:运行 Test5.java 文件,运行结果 如下所示 ->
可以看到执行了两条 SQL 语句;
第四步:将 Order.hbm.xml 中的 lazy 设置为 proxy ->
<many-to-one name="customer" class="com.hkl.pojo.Customer" column="cid" lazy="proxy"></many-to-one>
第五步:再次运行 Test5.java,结果如下图所示->
可以看到只有一条SQL语句了;
第六步:将Test5.java 文件中的 System.out.println(order); 改为以下语句时,再去运行 ->
System.out.println(order.getCustomer());
可以发现又变回两条SQL语句了->
那么这里再补充一下关于 proxy 和 no-proxy 的区别:
no-proxy:当调用方法需要访问customer的成员变量时,发送 SQL 语句查询 Customer,否则不查询;
proxy:无论调用方式是否需要访问 customer 的成员变量,都会发送 SQL 语句查询 Customer;
下面来说一下 多对多 的关系如何对操作 ->
多对多关系 课程与学生 -> 查询 课程 Course ,加载对应的 学生 Account ,默认延迟加载开启;
第一步:首先创建两个pojo实体类文件,Account.java 和 Course.java 和他们相对应的 xml 映射文件 ,如下所示->
Account.java->
package com.hkl.pojo;
import java.util.Set;
public class Account {
private Integer id;
private String name;
private Set<Course> courses;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Course.java ->
package com.hkl.pojo;
import java.util.Set;
public class Course {
private Integer id;
private String name;
private Set<Account> accounts;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Account> getAccounts() {
return accounts;
}
public void setAccounts(Set<Account> accounts) {
this.accounts = accounts;
}
@Override
public String toString() {
return "Course{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Course.hbm.xml 映射文件如下所示->
<?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>
<class name="com.hkl.pojo.Course" table="t_course">
<!-- 主键映射,数据库表中的主键字段用 id 配置,而 name = "id" 这个 id 指的是 Account 实体类中的 id 属性名-->
<id name="id" type="java.lang.Integer">
<!-- 数据库表 id 主键字段配置-->
<column name="id"></column>
<!-- 设置主键自增方式 -> identity-->
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<!--courses是实体类Course中的属性名,该属性是一个 Course 类的集合,所以对应表 account_course-->
<set name="accounts" table="account_course" lazy="true">
<!--这里配置一下主外键 aid -->
<key column="cid"></key>
<!--学生和选课的关系是多对多,所以这里是 many-to-many,然后给set类型加一个对象,对象类型是Course , column是course在这个中间表中的外键cid-->
<many-to-many class="com.hkl.pojo.Account" column="aid"></many-to-many>
</set>
</class>
</hibernate-mapping>
Account.hbm.xml 映射文件如下所示->
<?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>
<class name="com.hkl.pojo.Account" table="t_account">
<!-- 主键映射,数据库表中的主键字段用 id 配置,而 name = "id" 这个 id 指的是 Course 实体类中的 id 属性名-->
<id name="id" type="java.lang.Integer">
<!-- 数据库表 id 主键字段配置-->
<column name="id"></column>
<!-- 设置主键自增方式 -> identity-->
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<!--courses是实体类Course中的属性名,该属性是一个 Course 类的集合,所以对应表 account_course-->
<set name="courses" table="account_course">
<!--这里配置一下主外键 cid -->
<key column="aid"></key>
<!--学生和选课的关系是多对多,所以这里是 many-to-many,然后给set类型加一个对象,对象类型是Account , column是account在这个中间表中的外键aid-->
<many-to-many class="com.hkl.pojo.Course" column="cid"></many-to-many>
</set>
</class>
</hibernate-mapping>
第二步:创建测试 Test6.java 文件如下所示->
import com.hkl.pojo.Course;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test6 {
public static void main(String[] args) {
// 创建configuration
Configuration configuration = new Configuration().configure();
// 获取sessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
// 获取Session
Session session = sessionFactory.openSession();
Course course = session.get(Course.class,1);
System.out.println(course);
session.close();
}
}
运行结果如下所示 ->
可以发现只有一条 SQL 语句;
第三步:将 Test6.java 测试文件中的 System.out.println(course); 改为 ->
System.out.println(course.getAccounts());
再去运行,结果如下图所示 ->
可以看到执行了三条 SQL 语句【因为 多对多 关系之间有三张表】;
这里我们先把 Course.hbm.xml 中的 lazy 设置为 false 关掉延迟加载 ->
<set name="accounts" table="account_course" lazy="false">
<!--这里配置一下主外键 aid -->
<key column="cid"></key>
<!--学生和选课的关系是多对多,所以这里是 many-to-many,然后给set类型加一个对象,对象类型是Course , column是course在这个中间表中的外键cid-->
<many-to-many class="com.hkl.pojo.Account" column="aid"></many-to-many>
</set>
然后去运行 Test6.java 不管我们有没有级联操作都是执行两条 SQL 语句,而之前开启 延迟加载 之后会发现,当不涉及级联操作的时候就是一条 SQL 语句,涉及级联操作的时候才会变成两条 SQL 语句;
那么 多对多 关系两边是都一样的,这里 Account 和 Course 相同,所以 Account 就不做演示了;
这里和 一对多 的区别就是,当涉及级联操作的时候,一对多只需要查询两张表即可,而多对多关系中,需要三张表才能将他们两个关联起来,所以当多对多涉及级联操作的时候会执行三条 SQL 语句;如下图所示->