懒载入(Load On Demand)是一种独特而又强大的数据获取方法,它可以在用户滚动页面的时候自己主动获取很多其它的数据,而新得到的数据不会影响原有数据的显示,同一时候最大程度上降低server端的资源耗用。总结一句话:什么时候须要数据。什么时候载入。
一、懒载入
1.1 类的懒载入
由javassist产生的代理类与Classes类是继承关系。
session.load()方法产生的是代理对象,该代理类是持久化类的子类
/** * 类的懒载入 */ @Test public void testClass_lazy(){ session = HibernateUtils.openSession(); transaction = session.beginTransaction(); Classes classes = (Classes) session.load(Classes.class, 1L); //classes.setName("asdj"); System.out.println(classes.getName());//发出sql transaction.commit(); session.close(); }
1.2 集合的懒载入
/** * 集合的懒载入 */ @Test public void testCollect_lazy(){ session = HibernateUtils.openSession(); transaction = session.beginTransaction(); Classes classes = (Classes) session.get(Classes.class, 1L); Set<Student> students = classes.getStudents();//不发出 for (Student student : students) {//迭代的时候发出sql System.out.println(student.getName()); } transaction.commit(); session.close(); } /** * 更进一步的懒载入,设置extra,对于查询行数,最大值,最小值等 */ @Test public void testlazy_extra(){ session = HibernateUtils.openSession(); transaction = session.beginTransaction(); Classes classes = (Classes) session.get(Classes.class, 1L); Set<Student> students = classes.getStudents(); System.out.println(students.size()); transaction.commit(); session.close(); }
1.3 单端关联的懒载入(many2one的懒载入)
No-proxy 延迟载入 默认值
Proxy是加强版的延迟载入
由于是通过多的一方载入一的一方。所以对效率影响不大。所以普通情况下用默认值就可以。
依据多的一端载入一的一端,其实仅仅是多查了一条数据,对性能差点儿没有影响,比方依据学生来查班级
总结
懒载入是Hibernate提供的一种优化方式。
1、延迟载入在映射文件设置,而映射文件一旦确定,不能改动了。
2、延迟载入是通过控制sql语句的发出时间来提高效率的。
所以在开发中通常是不会去设置懒载入的配置。
二、抓取策略
抓取策略解决的是怎样载入Set集合中数据的问题
public class FetchTest { private Session session; private Transaction transaction; private SessionFactory sessionFactory; /** * fetch : select情况: * 先查找Classes的id,在依据id查Student * n+1条数据 * n:classes表中的条数 * 1:classes表本身 */ @Test public void testQueryAllStudent(){ session = HibernateUtils.openSession(); List<Classes> classes = session.createQuery("from Classes").list(); for (Classes classes2 : classes) { System.out.println(classes2.getName()); Set<Student> students = classes2.getStudents(); for (Student student : students) { System.out.println(student.getName()); } } session.close(); } /** * fetch : subselect情况: * 由于该需求含有子查询,所以fetch 使用 subselect * 2条sql */ @Test public void testQueryAllStudent2(){ session = HibernateUtils.openSession(); List<Classes> classes = session.createQuery("from Classes").list(); for (Classes classes2 : classes) { System.out.println(classes2.getName()); Set<Student> students = classes2.getStudents(); for (Student student : students) { System.out.println(student.getName()); } } session.close(); } /** * select * 先查询一的一方的所有的对象(Classes)。再依据每个对象的id值查询其关联对象(Student) */ @Test public void testQueryClassesByCidAndStudents_Select(){ Session session = HibernateUtils.openSession(); Classes classes = (Classes)session.get(Classes.class, 1L); System.out.println(classes.getName()); Set<Student> students = classes.getStudents(); for (Student student : students) { System.out.println(student.getName()); } session.close(); } /** * join 利用左外连接一条SQL语句把classes和student表所有查询出来了 * * 在含有子查询的需求分析中。利用join的抓取策略是不取的 * 1条sql */ @Test public void testQueryClassesByCidAndStudents_Join(){ Session session = HibernateUtils.openSession(); Classes classes = (Classes)session.get(Classes.class, 1L);//发出sql,故fetch为join的抓取,会导致懒载入的失效 System.out.println(classes.getName()); Set<Student> students = classes.getStudents(); for (Student student : students) { System.out.println(student.getName()); } session.close(); } }
总结:
由于抓取策略的设置在映射文件里,所以一旦映射文件生成就不能改变了。
通过发出SQL语句的不同的形式载入集合,从而优化效率的。
fetch为join的抓取策略会导致懒载入的失效在设为join时,他会直接将从表信息以join方式查询到而不是再次使用select查询。这样导致了懒载入的失效。
抓取策略和延迟载入的结合
Set集合
1、 当fetch为join时,lazy失效
2、 当fetch为select时
假设lazy为true/extra
当遍历集合的时候,发出载入集合的sql语句
假设lazy为false
当获取班级的时候,发出载入集合的sql语句
3、 当fetch为subselect时和上面的情况一致。