本项目比较适合初学者浏览。

Hibernate之lazy延迟加载,hibernatelazy延迟

一.延迟加载的概念

   当Hibernate从数据库中加载某个对象时,不加载关联的对象,而只是生成了代理对象,获取使用session中的load的方法(在没有改变lazy属性为false的情况下)获取到的也是代理对象,所以在上面这几种场景下就是延迟加载。

二.理解立即加载的概念

  当Hibernate从数据库中加载某个对象时,加载关联的对象,生成的实际对象,获取使用session中的get的方法获取到的是实际对象。

三.为什么要使用延迟加载

  延迟加载策略能避免加载应用程序不需要访问的关联对象,以提高应用程序的性能。

四.立即加载的缺点

Hibernate在查询某个对象时,立即查询与之关联的对象,我们可以看出这种加载策略存在两大不足:

1.select的语句数目太多,需要频繁的访问数据库,会影响查询的性能。

2.在应用程序只需要访问要的对象,而不需要访问与他关联的对象的场景下,加载与之关联的对象完全是多余的操作,这些多余的操作是会占内存,这就造成了内存空间的浪费。

五.什么时候使用延迟加载什么时候使用立即加载

   如果程序加载一个持久化对象的目的是为访问他的属性,则可以采用立即加载。如果程序加载一个持久化对象的目的仅仅是为了获得他的引用,则可以采用延迟加载。

六.Hibernate在对象-关系映射问价中配置加载策略

   I.类级别:

      <class>元素中lazy属性的可选值为true(延迟加载)和false(立即加载);

      <class>元素中的lazy属性的默认值为true

   II.一对多关联级别:

      <set>元素中的lazy属性的可选值为:true(延迟加载),extra(增强延迟加载)和false(立即加载);

      <set>元素中的lazy属性的默认值为true

   III.多对一关联级别:

      <many-to-one>元素中lazy属性的可选值为:proxy(延迟加载),no-proxy(无代理延迟加载)和false(立即加载)

      <many-to-one>元素中的lazy属性的默认值为proxy

   在下面的一些案例中都会以员工(Emp)的部门(Dept)的例子讲解:

   员工和部门是多对一的关系:

   关于员工和部门的Hibernate配置就不啰嗦了:可以看我的这篇博客:

I.1类级别的查询策略:

   01.立即加载案例:

     需求:通过Session的load()方法加载Dept对象时:

     首先在Dept.hbm.xml文件中配置lazy属性为false,表示立即加载。

 图片 1

 

@Test

public void loadDept() {

// 获取Session对象

Session session = HibernateUtil.currentSession();

// 如果通过load方式加载Dept对象

Dept dept=(Dept)session.load(Dept.class, 12);

      // 关闭session

HibernateUtil.closeSession();

}

 

   我们知道使用Load方法加载的是代理对象,只会在属性里保存一个OID,但是如果在Dept映射文件中配置了类级别的lazy为false就代表加载该对象时立即加载,也就是立即检索一道数据库,发出sql:

图片 2

图片 3

 

 

       02.延迟加载案例:

        同样是获取Dept对象,但是要把Dept.hbm.xml配置文件的类级别的lazy属性改为lazy=”true” 或者不写,应为类级别的lazy属性默认就是true,

 图片 4

 

@Test

public void loadDept() {

// 获取Session对象

Session session = HibernateUtil.currentSession();

// 如果通过load方式加载Dept对象

session.load(Dept.class, 12);

// 关闭session

HibernateUtil.closeSession();

}

 

  此时Dept.hbm.xml配置文件的类级别的lazy属性为true,则是延迟加载,那么load方法获取的知识Dept的代理对象,所以他不会去检索数据库。

 图片 5

 

II.1一对多和多对多关联的查询策略

  01.立即加载案例:

     在获取部门对象的时候同时获取员工对象:

设置Dept.hbm.xml 类级别的lazy属性为false;表示立即加载:

设置<set>元素的lazy属性为false,表示在加载部门的同时立即加载员工:

 图片 6

图片 7

 

   @Test

public void loadDept() {

// 获取Session对象

Session session = HibernateUtil.currentSession();

// 如果通过load方式加载Dept对象

Dept dept=(Dept)session.load(Dept.class, 12);

// 关闭session

HibernateUtil.closeSession();

}

  控制台输出结果:

 图片 8

 当你想获取一的一方(Dept)的对象同时,你也要加载多的一方(Emp)的对象,那么你要在一的一方(Emp)的<set>的节点上加上lazy=”false”表示立即加载,所以在使用Load方式加载Dept对象的时候,Emp对象也会不加载出来,所以程序在运行到Dept
dept=(Dept)session.load(Dept.class, 12);会发出两条sql语句:

第一条是查询部门的信息,第二条sql是根据部门编号去数据库中检索员工信息。

  02.延迟加载:

     
如果把上面的案例<set>节点的属性lazy改为trur,或者默认不写,那么在加载Dept对象的时候,就不会再去加载Emp对象,而且只会发出一条sql,这条sql就是指检索部门的信息。

 图片 9

      03.增强延迟加载:

   当<set>元素中配置lazy的属性为extra,表明是增强延迟加载策略。

图片 10

 

 
其实增强延迟加载策略与一般的延迟加载策略lazy=”true”非常相似。他们主要区别在于,我们看到这个名词增强延迟加载,顾名思义就是这个策略能在进一步的帮我延迟加载这个对象,也就是代理对象的初始化时机。

     演示案例:

         01.
当set节点的lazy属性为true,或者不写的话(取默认值),那么执行以下语句:

           

@Test
    public void loadDept() {
        // 获取Session对象
        Session session = HibernateUtil.currentSession();
        // 如果通过load方式加载Dept对象
        Dept dept=(Dept)session.load(Dept.class, 12);
        //拿该部门下的员工的人数:也就是集合的大小
        dept.getEmps().size();
        // 关闭session
        HibernateUtil.closeSession();
    }

      输出结果:

    图片 11

 

      02. 当set节点的lazy属性为extra那么执行以下语句:

       

@Test
    public void loadDept() {
        // 获取Session对象
        Session session = HibernateUtil.currentSession();
        // 如果通过load方式加载Dept对象
        Dept dept=(Dept)session.load(Dept.class, 12);
        //拿该部门下的员工的人数:也就是集合的大小
        dept.getEmps().size();
        // 关闭session
        HibernateUtil.closeSession();
    }

     输出结果:

     图片 12

 

    III.1多对一关联的查询策略

       
 在映射文件中,<many-to-one>元素用来设置多对一的关系,在Emp.hbm.xml文件中表明Emp类到Dept类的多对一的关联关系:

    图片 13

 

     01.延迟加载

        需求:获取Emp对象,但是并不去加载与之关联的Dept对象。

     
 首先要设置<many-to-one>节点的lazy属性为proxy,表示延迟加载。

      

@Test
public void loadEmp() {
// 获取Session对象
Session session = HibernateUtil.currentSession();
// 如果通过load方式加载Dept对象
Emp emp=(Emp)session.get(Emp.class, 1);

//获取Dept对象,因为此时的配置文件lazy是proxy,所以是代理对象
Dept dept=emp.getDept();
// 关闭session
HibernateUtil.closeSession();
}

      控制台输出结果:

      图片 14

 

   
结果大家可想而知:<many-to-one>节点的lazy属性为proxy,表示延迟加载。在加载Emp对象的时候会发出sql去查询数据库,但是在获取Dept对象的时候延迟加载了,所以不会发出sql。

     

       02.无代理延迟加载:

 

           
在<many-to-one>元素中配置lazy属性为no-proxy,表示无代理延迟加载。

           
 图片 15

        

@Test
public void loadEmp() {
// 获取Session对象
Session session = HibernateUtil.currentSession();
// 如果通过load方式加载Dept对象
Emp emp=(Emp)session.get(Emp.class, 1);

//获取Dept对象,因为此时的配置文件lazy是proxy,所以是代理对象
Dept dept=emp.getDept();
// 关闭session
HibernateUtil.closeSession();
}

           
此程序在加载的Emp对象dept属性为NULL,当程序运行到第3行的时候将触发Hibernate执行查询Dept表的select语句,,从而加载Dept对象,由此可见,当lazy属性为proxy时,可以延长延迟加载Dept代理对象的时间,而lazy属性为no-proxy时,则可以避免使用由Hibernate提供的Dept代理类实例,是Hibernate对程序提供更加透明的持久化服务。

     03.立即加载:

       
  首先要设置<many-to-one>节点的lazy属性为false,表示立即加载。

       
  图片 16

           

@Test
public void loadEmp() {
// 获取Session对象
Session session = HibernateUtil.currentSession();
// 如果通过load方式加载Dept对象
Emp emp=(Emp)session.get(Emp.class, 1);

//获取Dept对象,因为此时的配置文件lazy是false,所以是实际对象
Dept dept=emp.getDept();
// 关闭session
HibernateUtil.closeSession();
}

    控制台输出结果:

       图片 17

 

        

 

 

      

 

一.延迟加载的概念 当 Hibernate
从数据库中加载某个对象时,不加载关联的对象,而只是生成了代理对…

一.延迟加载的概念

具体流程就是:当访问首页index.jsp时,加载框架,显示head.jsp里的内容,里面的下拉框的option值是从数据库里取出来显示的(通过List getDeptno()方法从数据库里取出deptno),当点击其中一个选项时,由jQuery传值到后台的同时页面在framenamemain的框架里加载,在EmpListServlet获取到前台传过来的deptno的值,再通过List<Emp> findByDno(int deptno)获取到Emp对象信息的list集合,最后将请求转发给listEmp.jsp显示。

   当Hibernate从数据库中加载某个对象时,不加载关联的对象,而只是生成了代理对象,获取使用session中的load的方法(在没有改变lazy属性为false的情况下)获取到的也是代理对象,所以在上面这几种场景下就是延迟加载。

  1. 实体类Emp

二.理解立即加载的概念

  当Hibernate从数据库中加载某个对象时,加载关联的对象,生成的实际对象,获取使用session中的get的方法获取到的是实际对象。

package com.chinasofti.domain;import java.util.Date;public class Emp { private int empno; private String ename; private String job; private int mgr; private Date hireDate; private double sal; private double comm; private int deptno; public Emp() { super(); } public Emp(int empno, String ename, String job, int mgr, Date hireDate, double sal, double comm, int deptno) { this.empno = empno; this.ename = ename; this.job = job; this.mgr = mgr; this.hireDate = hireDate; this.sal = sal; this.comm = comm; this.deptno = deptno; } public int getEmpno() { return empno; } public void setEmpno(int empno) { this.empno = empno; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public int getMgr() { return mgr; } public void setMgr { this.mgr = mgr; } public Date getHireDate() { return hireDate; } public void setHireDate(Date hireDate) { this.hireDate = hireDate; } public double getSal() { return sal; } public void setSal(double sal) { this.sal = sal; } public double getComm() { return comm; } public void setComm(double comm) { this.comm = comm; } public int getDeptno() { return deptno; } public void setDeptno(int deptno) { this.deptno = deptno; } @Override public String toString() { return "Emp{" + "empno=" + empno + ", ename='" + ename + ''' + ", job='" + job + ''' + ", mgr=" + mgr + ", hireDate=" + hireDate + ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + '}'; }}

三.为什么要使用延迟加载

  1. EmpDao和EmpDaoImpl

  延迟加载策略能避免加载应用程序不需要访问的关联对象,以提高应用程序的性能。

四.立即加载的缺点

package com.chinasofti.dao;import com.chinasofti.domain.Emp;import java.util.List;public interface EmpDao { //部门编号遍历 List getDeptno(); //根据部门编号查找雇员信息 List<Emp> findByDno(int deptno);}

package com.chinasofti.dao.impl;import com.chinasofti.dao.EmpDao;import com.chinasofti.domain.Emp;import com.chinasofti.utils.JdbcUtilsSingle;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;public class EmpDaoImpl implements EmpDao { @Override public List<Emp> findByDno(int deptno) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List<Emp> list = new ArrayList(); try { conn = JdbcUtilsSingle.getInstance().getConnection(); String sql = "select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where deptno=?"; ps = conn.prepareStatement; ps.setInt(1, deptno); rs = ps.executeQuery(); while ) { Emp e = mappingEmp; list.add; } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtilsSingle.getInstance().release(rs, ps, conn); } return list; } private Emp mappingEmp(ResultSet rs) throws SQLException { Emp e = new Emp(); e.setEmpno(rs.getInt; e.setEname(rs.getString; e.setJob(rs.getString; e.setMgr(rs.getInt; e.setHireDate(rs.getDate("hiredate")); e.setSal(rs.getDouble; e.setComm(rs.getDouble; e.setDeptno(rs.getInt); return e; } @Override public List getDeptno() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; List list = new ArrayList(); try { conn = JdbcUtilsSingle.getInstance().getConnection(); String sql = "select distinct deptno from emp"; ps = conn.prepareStatement; rs = ps.executeQuery(); while ) { list.add(rs.getInt); } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtilsSingle.getInstance().release(rs, ps, conn); } return list; }}

Hibernate在查询某个对象时,立即查询与之关联的对象,我们可以看出这种加载策略存在两大不足:

  1. service层EmpService和EmpServiceImpl

1.select的语句数目太多,需要频繁的访问数据库,会影响查询的性能。

2.在应用程序只需要访问要的对象,而不需要访问与他关联的对象的场景下,加载与之关联的对象完全是多余的操作,这些多余的操作是会占内存,这就造成了内存空间的浪费。

package com.chinasofti.service;import com.chinasofti.domain.Emp;import java.util.List;public interface EmpService { List getDeptno(); List<Emp> findByDno(int deptno);}

package com.chinasofti.service.impl;import com.chinasofti.dao.EmpDao;import com.chinasofti.dao.impl.EmpDaoImpl;import com.chinasofti.domain.Emp;import com.chinasofti.service.EmpService;import java.util.List;public class EmpServiceImpl implements EmpService { private EmpDao empDao = new EmpDaoImpl(); @Override public List getDeptno() { return empDao.getDeptno(); } @Override public List<Emp> findByDno(int deptno) { return empDao.findByDno; }}

五.什么时候使用延迟加载什么时候使用立即加载

  1. 显示层index.jsp,head.jsp,listEmp.jsp

   如果程序加载一个持久化对象的目的是为访问他的属性,则可以采用立即加载。如果程序加载一个持久化对象的目的仅仅是为了获得他的引用,则可以采用延迟加载。

index.jsp

六.Hibernate在对象-关系映射问价中配置加载策略

<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>雇员列表</title></head><frameset rows="20%,*" frameborder="no"> <frame name="head" src="${pageContext.request.contextPath}/DeptnoServlet"> <frame name="main" src=""></frameset></html>

   I.类级别:

head.jsp

      <class>元素中lazy属性的可选值为true(延迟加载)和false(立即加载);

<%@ page contentType="text/html;charset=UTF-8" language="java" %><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><html><head> <title>头部</title> <script src="js/jquery-1.10.2.min.js" language="JavaScript"></script> <script type="text/javascript"> $(function () { $("#select").change(function () { var deptno = $.val(); $("this #no_select").attr("disabled", "disabled"); window.parent.main.location.href = "${pageContext.request.contextPath}/EmpListServlet?deptno=" + deptno; }); }); </script></head><body style="text-align: center;"><h1>雇员列表</h1><br>部门编号:<select name="deptno" style="width: 100px;"> <option value="0" selected style="color: darkgray">请选择:</option> <c:forEach var="dno" items="${list}"> <option value="${dno}">${dno}</option> </c:forEach></select></body></html>

      <class>元素中的lazy属性的默认值为true

listEmp.jsp

   II.一对多关联级别:

<%@ page contentType="text/html;charset=UTF-8" language="java" %><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><html><head> <title>雇员列表展示界面</title></head><body style="text-align: center;"><table border="1" align="center" cellpadding="0" cellspacing="0"> <tr> <td>雇员编号</td> <td>雇员姓名</td> <td>雇员工作</td> <td>上级编号</td> <td>雇用日期</td> <td>雇员工资</td> <td>雇员奖金</td> <td>部门编号</td> </tr> <c:forEach var="c" items="${list}"> <tr> <td>${c.empno}</td> <td>${c.ename}</td> <td>${c.job}</td> <td>${c.mgr}</td> <td>${c.hireDate}</td> <td>${c.sal}</td> <td>${c.comm}</td> <td>${c.deptno}</td> </tr> </c:forEach></table></body></html>

      <set>元素中的lazy属性的可选值为:true(延迟加载),extra(增强延迟加载)和false(立即加载);

  1. 控制层DeptnoServlet和EmpListServlet

      <set>元素中的lazy属性的默认值为true

DeptnoServlet

   III.多对一关联级别:

package com.chinasofti.web;import com.chinasofti.service.EmpService;import com.chinasofti.service.impl.EmpServiceImpl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.List;@WebServlet(name = "DeptnoServlet", urlPatterns = "/DeptnoServlet")public class DeptnoServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { EmpService empService = new EmpServiceImpl(); List list = empService.getDeptno(); request.setAttribute("list", list); request.getRequestDispatcher("/head.jsp").forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}

      <many-to-one>元素中lazy属性的可选值为:proxy(延迟加载),no-proxy(无代理延迟加载)和false(立即加载)

EmpListServlet

      <many-to-one>元素中的lazy属性的默认值为proxy

package com.chinasofti.web;import com.chinasofti.domain.Emp;import com.chinasofti.service.EmpService;import com.chinasofti.service.impl.EmpServiceImpl;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.List;@WebServlet(name = "EmpListServlet", urlPatterns = "/EmpListServlet")public class EmpListServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding; int deptno = Integer.parseInt(request.getParameter); System.out.println; EmpService empService = new EmpServiceImpl(); List<Emp> list = empService.findByDno; request.setAttribute("list",list); request.getRequestDispatcher("/listEmp.jsp").forward(request,response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}

   在下面的一些案例中都会以员工(Emp)的部门(Dept)的例子讲解:

源代码:

   员工和部门是多对一的关系:

   关于员工和部门的Hibernate配置就不啰嗦了:可以看我的这篇博客:

I.1类级别的查询策略:

   01.立即加载案例:

     需求:通过Session的load()方法加载Dept对象时:

     首先在Dept.hbm.xml文件中配置lazy属性为false,表示立即加载。

 图片 18

 

@Test

public void loadDept() {

// 获取Session对象

Session session = HibernateUtil.currentSession();

// 如果通过load方式加载Dept对象

Dept dept=(Dept)session.load(Dept.class, 12);

      // 关闭session

HibernateUtil.closeSession();

}

 

   我们知道使用Load方法加载的是代理对象,只会在属性里保存一个OID,但是如果在Dept映射文件中配置了类级别的lazy为false就代表加载该对象时立即加载,也就是立即检索一道数据库,发出sql:

图片 19

图片 20

 

 

       02.延迟加载案例:

发表评论

电子邮件地址不会被公开。 必填项已用*标注