3.0、Hibernate-延迟加载 1
Hibernate 延迟加载 也叫 惰性加载、懒加载;
使用延迟加载可以提高程序运行效率,Java 程序 与 数据库交互的频次越低,程序运行的效率就越高,所以我们应该尽量减少 Java 程序 与 数据库的交互次数,Hibernate 延迟加载 就很好的做好了这一点;
先来说一下没有延迟加载怎么操作 -> 客户 和 订单,当我们查询客户对象时,因为有级联设置,所以会将对应的订单信息一并查询出来,这样就需要发送两条 SQL 语句,分别查询 客户信息 和 订单信息。
延迟加载的思路是 -> 当我们查询客户的时候,如果没有访问订单数据,就只发送一条 SQL 语句来查询客户信息,如果需要访问订单数据的时候,则发送两条 SQL;
所以延迟加载可以看做是一种优化机制,根据具体的需求,自动选择要执行的 SQL 语句数量
接下来用代码演示 一对多 - 延迟加载 ->
第一步:用之前 1.0 里面创建好的素材就好,这里先测试 一对多 所以用到的是 customer 和 order 这两个 pojo 实体类,查询 customer 对 order 进行延迟加载,在 customer.hbm.xml 映射文件中进行设置,延迟加载默认开启;将lazy属性设置为 true ,不过这个lazy默认就是开启的 ->
<!-- orders是实体类Customer中的属性名,该属性是一个Order类的集合,所以对应表 order-->
<set name="orders" table="orders" lazy="true">
<!-- 这里配置一下主外键 cid -->
<key column="cid"></key>
<!-- 消费者和订单的关系是一对多,所以这里是 one-to-many,然后给set类型加一个对象,对象类型是Order-->
<one-to-many class="com.hkl.pojo.Order"></one-to-many>
</set>
第二步:在 test 文件夹下创建 Test4.java 文件去查询一下 customer ->
import com.hkl.pojo.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test4 {
public static void main(String[] args) {
// 创建configuration
Configuration configuration = new Configuration().configure();
// 获取sessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
// 获取Session
Session session = sessionFactory.openSession();
Customer customer = session.get(Customer.class,42);
System.out.println(customer);
session.close();
}
}
运行之后我们会发现报了一个错误 -> StackOverflowError 栈溢出;这是因为 Customer 和 Order 两个 pojo 实体类中都有 toString() 方法而这两个方法中都相互调用了对方的一个对象 ,而在 Java 中栈的空间是有限的不断的去创建对象一定会导致栈溢出,如下->
//在 Customer.java pojo实体类中,有一个 Set 类型的集合类 Order
private Set<Order> orders;
//在 Order.java pojo实体类中有一个Customer类型的对象 customer
private Customer customer;
解决方案 -> 将其中一个 pojo 实体类中的 toString() 方法去掉 或者 将其中一个 toString() 方法让他不要调用另一个 pojo 类的对象即可;成功查询 ->
这时候我们只是查询一张表 customer ,如果我们把 Test4.java 文件中的 ->
System.out.println(customer);
改为 ->
System.out.println(customer.getOrders());
可以发现有两条 SQL 语句,查询了两次 ->
这个例子体现出了 Hibernate 延迟加载的作用,会自动的根据当前的需求来选择要查询的语句,如果你只需要查询主表的信息那么一条 SQL 语句就搞定,但是如果要把从表的数据能够带出来就会调用两条 SQL 语句;
但是如果我们把延迟加载关掉 -> lazy = "false"
<!-- orders是实体类Customer中的属性名,该属性是一个Order类的集合,所以对应表 order-->
<set name="orders" table="orders" lazy="false">
<!-- 这里配置一下主外键 cid -->
<key column="cid"></key>
<!-- 消费者和订单的关系是一对多,所以这里是 one-to-many,然后给set类型加一个对象,对象类型是Order-->
<one-to-many class="com.hkl.pojo.Order"></one-to-many>
</set>
再去只查询主表 customer 会发现还是有两条 SQL 语句 ->
这是因为我们把延迟加载关掉了,他就变成立刻加载了,只要查询主表就会把从表带出来~
lazy知识补充:
这里再补充一点:lazy除了可以设置 true 和 false 之外,还可以设置 extra ,extra 是比 true 更加懒惰的一种加载方式,或者说是更加智能的一种加载方式,下面我们通过例子来演示一下 ->
我们测试一下 -> 先将 lazy 设置为 true 查询 Customer 对象,然后打印该对象对应的 orders 集合的长度;
可以看到查询了两条 SQL 语句,并且打印出来 长度是 1 ;
比如说我们有三条数据,他会先把这三条数据查询出来然后封装成三个对象,然后再把这三个对象装载到一个集合里面,之后将这个集合赋给我们的 customer,最后然后再从集合里面调用 Set;
相当于先把对象装到集合里面然后再去判断集合的长度,这样其实是有点浪费我们资源的,因为我们只需要判断长度,我并不需要知道他具体的信息是什么;
然后将 lazy 设置为 extra,再跑一遍结果如下->
这里我们只需要判断有几条数据就可以了,并不需要像之前那样将每条数据封装成对象,再把对象装载到集合里,再去判断集合的长度的一系列操作;
与刚刚的语句相比较更为的方便、高效、合理;