• Hibernate之lazy延迟加载(转)


    一.延迟加载的概念

       当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配置就不啰嗦了:可以看我的这篇博客:http://www.cnblogs.com/heyongjun1997/p/5767187.html

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

       01.立即加载案例:

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

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

     

    @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:

           02.延迟加载案例:

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

     

    @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的代理对象,所以他不会去检索数据库。

     

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

      01.立即加载案例:

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

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

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

     

       @Test
    
    public void loadDept() {
    
    // 获取Session对象
    
    Session session = HibernateUtil.currentSession();
    
    // 如果通过load方式加载Dept对象
    
    Dept dept=(Dept)session.load(Dept.class, 12);
    
    // 关闭session
    
    HibernateUtil.closeSession();
    
    }

      控制台输出结果:

     

     当你想获取一的一方(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就是指检索部门的信息。

     

          03.增强延迟加载:

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

      其实增强延迟加载策略与一般的延迟加载策略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();
        }

          输出结果:

        

          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();
        }

         输出结果:

         

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

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

        

         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();
    }

          控制台输出结果:

          

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

         

           02.无代理延迟加载:

                在<many-to-one>元素中配置lazy属性为no-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();
    }

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

         03.立即加载:

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

              

               

    @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();
    }

        控制台输出结果:

           

    转:http://www.cnblogs.com/heyongjun1997/p/5775033.html

    谢!

  • 相关阅读:
    【opencv.js】将图片转换为灰度图
    【快速创建】第一个 opencv.js 项目
    【踩坑无数】Anaconda(2020.02) + Tensorflow2.1 + python3.7 (CPU版本)的安装
    Thread的join方法
    常用语句
    获取当前托管线程的唯一标识符
    修改文件或文件夹的权限,为指定用户、用户组添加完全控制权限(转载)
    C#中Monitor和Lock以及区别(转载)
    LIBRA查询
    Select()和SelectMany()的区别
  • 原文地址:https://www.cnblogs.com/zhangzongle/p/5781682.html
Copyright © 2020-2023  润新知