前言
先来看看面试题:
Hibernate中get和load方法的区别?
答:相同点:都是通过主键查询的方法。session.get(User.class,1);session.load(User.class,1);
不同点:
get: 及时加载,只要调用get方法立刻向数据库查询,,执行sql语句。
load:默认使用懒加载,当用到数据的时候才向数据库查询。 相当于做了一层优化。
懒加载:(lazy)
概念:当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性。
目的:提供程序执行效率!
在配置文件中设置lazy 值:
true 默认情况下使用懒加载
false 关闭懒加载
extra (在集合数据懒加载时候提升效率)
在真正使用数据的时候才向数据库发送查询的sql;
如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!
集合属性默认有懒加载!
案例分析:
本本案列均来自Hibernate系列篇中讲解了部门与员工的案例,这里直接拿代码来测试了。如有不明白的地方,请参考作者之前的Hibernate笔记。
先测试get方法—Lazy使用默认值true.
@Test
public void get_load() {
Session session = sf.openSession();
session.beginTransaction();
Dept dept = new Dept();
// get: 及时查询
dept = (Dept) session.get(Dept.class, 9);
System.out.println(“---------------------------”);
System.out.println(dept.getDeptName());
session.getTransaction().commit();
session.close();
}
打印结果:先打印sql语句,再打印“————”,最后打印部门名称。说明get方法是直接执行数据库查询的(不犹豫,很果断)。
测试load方法
@Test
public void get_load() {
Session session = sf.openSession();
session.beginTransaction();
Dept dept = new Dept();
// get: 及时查询
// dept = (Dept) session.get(Dept.class, 9);
// System.out.println(dept.getDeptName());
// load,默认懒加载, 及在使用数据的时候,才向数据库发送查询的sql语句!
dept = (Dept)session.load(Dept.class, 9);
System.out.println(“---------------------------”);
// 在这里使用
System.out.println(dept.getDeptName());
session.getTransaction().commit();
session.close();
}
打印结果;先打印“—————–”,再打印sql查询语句,最后再打印部门的名称。说明load方法使用了懒加载机制,在用到dept数据的时候才向数据库发送查询的sql语句!
注意:在session关闭之后,不能使用懒加载数据,也就是load查询到的数据比如user对象,如果在session.close()之后,进行user.getName()将会报错。
比如:代码如下:
@Test
public void get_load() {
Session session = sf.openSession();
session.beginTransaction();
Dept dept = new Dept();
// get: 及时查询
// dept = (Dept) session.get(Dept.class, 9);
// System.out.println(dept.getDeptName());
// load,默认懒加载, 及在使用数据的时候,才向数据库发送查询的sql语句!
dept = (Dept)session.load(Dept.class, 9);
System.out.println(“---------------------------”);
session.getTransaction().commit();
session.close();
// 在这里使用
System.out.println(dept.getDeptName());
}
会报错!错误信息:org.hibernate.LazyInitializationException: could not initialize proxy - no Session
还有,在使用load方法时将会返回查询结果的代理对象。
例如:user=(User)session.load(User.class,1); 此时的user类型为User对象的代理对象。我们可以通过debug断点调试的方法查看dept的类型发生了变化。
懒加载在集合中的应用:
@Test
public void set() {
Session session = sf.openSession();
session.beginTransaction();
Dept dept = (Dept) session.get(Dept.class, 10);
System.out.println(dept.getDeptName());
System.out.println("------");
System.out.println(dept.getEmps()); // SQL
session.getTransaction().commit();
session.close();
}
打印顺序:先查询部门的sql语句,然后打印部门的名称,再打印“———–”,然后查询员工的sql语句,最后打印该部门下的全部的员工。这就是懒加载在集合中的应用,即如果在具体的实际开发中,我们只想要部门的名称等信息,不会去关心该部门下的具体员工,那么将lazy=true,会提高Hibernate对数据库操作的效率。
但是有些时候,我们又想查询部门的时候,也同时查出来员工的信息,那么就必须把lazy改为flase.因为有时在实际的项目中查询跟数据库操作有关,一般会放在service层中,如果在页面加载之前调用一次service层中的方法,就想查询部门和员工的信息,并且在页面中显示,那么怎么办呢?这就考虑关闭懒加载了。之后的项目开发案例中会给出具体的应用。
那么还有一点,如何解决session关闭后不能使用懒加载数据的问题?
// 方式1: 在session关闭之前先使用一下数据
//dept.getDeptName();
// 方式2:session关闭之前强迫代理对象初始化
Hibernate.initialize(dept);
// 方式3:关闭懒加载
设置lazy=false;
// 方式4: 在使用数据之后,再关闭session!
测试代码如下:
@Test
public void get_load() {
Session session = sf.openSession();
session.beginTransaction();
Dept dept = new Dept();
// get: 及时查询
// dept = (Dept) session.get(Dept.class, 9);
// System.out.println(dept.getDeptName());
// load,默认懒加载, 及在使用数据的时候,才向数据库发送查询的sql语句!
dept = (Dept)session.load(Dept.class, 9);
// 方式1: 先使用一下数据
//dept.getDeptName();
// 方式2:强迫代理对象初始化
Hibernate.initialize(dept);
// 方式3:关闭懒加载
session.getTransaction().commit();
session.close();
// 在这里使用
System.out.println(dept.getDeptName());
}
最后,说一下集合中lazy=extra 的用法。
如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!
测试:
@Test
public void set() {
Session session = sf.openSession();
session.beginTransaction();
Dept dept = (Dept) session.get(Dept.class, 10);
System.out.println(dept.getDeptName());
System.out.println("------");
System.out.println(dept.getEmps().isEmpty()); // SQL
session.getTransaction().commit();
session.close();
}
输出顺序:部门名称,“—-”然后是“select count(id) form t_employee‘’的sql语句,说明size或者isEmpty方法只会查询员工表的总记录数,不会查询员工的全部信息。这也算是一种优化策略!