zoukankan      html  css  js  c++  java
  • hibernate 延迟加载

    延迟加载
    延迟加载:
    当hibernate从数据库中加载某个对象时,不加载关联的对象,而只是生成了代理对象。使用session中的load的方法(在没有改变lazy属性,属性值为true的情况下)获取到的也是代理对象。

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

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

    立即加载的缺点:
    Hibernate在查询某个对象时,立即查询与之关联的对象:
    1、当select的语句数目太多,需要频繁的访问数据库,会影响查询的性能。
    2、在应用程序只需要访问要的对象,而不需要访问与他关联的对象的场景下,加载与之关联的对象完全是多余的操作,这些多余的操作是会占内存,这就造成了内存空间的浪费。

    延迟加载的原理图: 

    Hibernate的lazy生效期:
    生效期和session一样的,session关闭,lazy失效。hibernate支持lazy策略只在session打开状态下有效。如果session已经关闭了,则会抛出LazyInitalizationException异常
    Hibernate lazy属性,在3.x后是默认打开的,在以前版本中默认是关闭的


    hibernate在对象关系映射文件中配置加载策略的方式:(lazy)
    1、类级别
    元素中lazy属性的可选值为true(延迟加载)和false(立即加载);
    元素中的lazy属性的默认值为true
    2、一对多关联级别:
    元素中的lazy属性的可选值为:true(延迟加载),extra(增强延迟加载)和false(立即加载);
    元素中的lazy属性的默认值为true
         extra其实是一种比较智能的延迟加载,即调用集合的size/contains等方法的时候,hibernate并不会去加载整个集合的数据,而是发出一条聪明的SQL语句,以便获得需要的值,只有在真正需要用到这些集合元素对象数据的时候,才去发出查询语句加载所有对象的数据。
    3、多对一关联级别:
    元素中lazy属性的可选值为:proxy(延迟加载),no-proxy(无代理延迟加载)和false(立即加载)
    元素中的lazy属性的默认值为proxy

    load和hibernate的主要的区别:
    1、load采用的是延迟加载,get 不能采用延迟加载技术而是立刻加载
    2、load方法认为数据库中一定存在要检索的数据,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,那么只能抛出异常ObjectNotFoundException;而对于get方法,Hibernate一定要获取到真实的数据才会返回对象,否则返回null。
    3、load方法可以返回一个没有加载实体数据的代理类实例,而get方法永远返回有实体数据的对象。
    (对于load和get方法返回类型:好多书中都说:“get方法永远只返回实体类”,实际上并不正确,get方法如果在session缓存中找到了该id对应的对象,如果刚好该对象前面是被代理过的,如被load方法使用过,或者被其他关联对象延迟加载过,那么返回的还是原先的代理对象,而不是实体类对象,如果该代理对象还没有加载实体数据(就是id以外的其他属性数据),那么它会查询二级缓存或者数 据库来加载数据,但是返回的还是代理对象,只不过已经加载了实体数据。)

    下面介绍get和post方法的具体用法及事例。

    我的工具类:主要是用来创建session工厂并打开session的。下面两个事例中会用到这个类

    public class SessionFactoryUtils {
        private SessionFactory factory;
        private static SessionFactoryUtils factoryUtils;
    
        // 单例模式:把构造方法设置为私有的,说明不可以new这个类的实例。
        private SessionFactoryUtils() {
        }
    
        // 通过定义这个类的静态方法,并且返回类型与这个类的类型一样,来实现对这个类的访问
        public static SessionFactoryUtils getInstance() {
            if (factoryUtils == null) {
                factoryUtils = new SessionFactoryUtils();
            }
            return factoryUtils;
        }
    
        public SessionFactory openSessionFactory() {
            if (factory == null) {
                //加载主配置文件
                Configuration configuration = new Configuration().configure();
    
                //建立工厂
                factory = configuration.buildSessionFactory();
            }
            return factory;
        }
    }

    get方法的加载方式
    1、因为hibernate规定get方法不使用延迟加载,所以hibernate会去确认该id对应的数据是否存在
    2、它会首先在session缓存中查找
    3、如果session中找不到,就会去二级缓存中查找
    4、如果二级缓存中还是没有找到,就会去数据库中查找
    5、如果数据库中还是找不到就返回null。

    代理对象实际就是空的对象,并没有去数据库中查询,所以我们叫做代理对象。如果取数据库查询了,返回了真实的对象,我们就叫做实体对象。

    junit测试类:测试get方法

    @org.junit.Test
    public void query() {
        //调用我上面定义的工具类,通过调用定义的方法来创建session工厂并打开session
        private  SessionFactory sessionFactory = SessionFactoryUtils.getInstance().openSessionFactory();
        Session session = sessionFactory.openSession();
    
        Admins adminsGet = session.get(Admins.class, 4);
        System.out.println(adminsGet);
    }

    控制台输出:可以发现在直接得到id的时候,它就发起了sql语句去数据库中查询了。并没有延迟加载。

    Hibernate: select admins0_.aid as aid1_0_0_, admins0_.adminname as adminnam2_0_0_, admins0_.adminpwd as adminpwd3_0_0_ from admins admins0_ where admins0_.aid=?
    4
    -------
    4,nowyou

    Load的加载方式
    1、Load采用延迟加载的方式,hibernate的思想是既然这个方法支持延迟加载,它就认为这个对象一定在数据库中存在,可以放心的使用代理来延迟加载,如果在使用过程中出现了问题就放心的抛异常
    2、Load方法会首先查询session缓存,看缓存中有没有这个对象
    3、如果缓存中没有这个对象就会去创建个代理对象来管理,因为延迟加载需要代理来执行。但是并没有去数据库中查询
    4、只有当你实际使用这个对象的时候,它才会触发sql语句。这个时候hibernate就会去查询二级缓存和数据库,如果数据库中没有这条语句,就抛出异常ObjectNotFoundException。

    hibernate load方法加载实体对象的时候,会根据映射文件上 类级别 lazy属性值的配置,分情况讨论:
    (1)若为true,即为延迟加载,就是上面的模式
    (2)若为false,即为非延迟加载,即立即加载。就跟get方法查找顺序一样,只是最终若没发现符合条件的记录,则会抛出一个ObjectNotFoundException。
    junit测试类:load方法:

    @org.junit.Test
        public void query() {
            //调用我上面定义的工具类,通过调用定义的方法来创建session工厂并打开session
            private  SessionFactory sessionFactory = SessionFactoryUtils.getInstance().openSessionFactory();
            Session session = sessionFactory.openSession();
    
             Admins adminsLoad = session.load(Admins.class, 4);
             System.out.println(adminsLoad.getAid());
             System.out.println("-------");
    
             System.out.println(adminsLoad.getAid()+","+adminsLoad.getAdminname());
        }

    1、当类级别lazy属性值为false,即不适用延迟加载的时候:

    <hibernate-mapping>
        <class name="org.danni.model.entity.Admins" table="admins" lazy="false">
            <id name="aid" column="aid">
                <generator class="native"></generator>
            </id>
            <property name="adminname" column="adminname"></property>
            <property name="adminpwd" column="adminpwd"></property>
        </class>
    </hibernate-mapping>

    控制台输出:可以发现没有采用延迟加载,当直接输出id就调用了sql去查询,采用立即查询的方式

    Hibernate: select admins0_.aid as aid1_0_0_, admins0_.adminname as adminnam2_0_0_, admins0_.adminpwd as adminpwd3_0_0_ from admins admins0_ where admins0_.aid=?
    4
    -------
    4,nowyou

    2、当lazy属性为true的时候,即采用延迟加载:

    <hibernate-mapping>
        <class name="org.danni.model.entity.Admins" table="admins" lazy="true">
            <id name="aid" column="aid">
                <generator class="native"></generator>
            </id>
            <property name="adminname" column="adminname"></property>
            <property name="adminpwd" column="adminpwd"></property>
        </class>
    </hibernate-mapping>

    控制台输出:可以发现,当只是得到id的值的时候并没有取数据库中查询,而是创建了个代理对象来管理。这个代理对象中只保存了实体对象的id。但是当使用这个对象,获得这个对象的名字的时候他才触发了sql语句,它才去二级缓存、数据库中查找。

    4
    -------
    Hibernate: select admins0_.aid as aid1_0_0_, admins0_.adminname as adminnam2_0_0_, admins0_.adminpwd as adminpwd3_0_0_ from admins admins0_ where admins0_.aid=?
    4,nowyou


    原文链接:https://blog.csdn.net/qq_36748278/article/details/78048406

  • 相关阅读:
    【转载】动态加载wpf控件主题样式资源
    paip.批处理清理java项目冗余jar的方法
    paip.java OutOfMemoryError 解决方法o33
    paip.java win程序迁移linux的最佳实践
    paip.java c# .net php python调用c++ c dll so windows api 总结
    paip.提高效率微信 手机app快速开发平台—微网络撬动大市场
    paip.Log4j配置不起作用的解决
    paip.获取地理位置根据Ip
    paip.java 开发中web server的选择jboss resin tomcat比较..
    paip.提升安全性Des加密 java php python的实现总结
  • 原文地址:https://www.cnblogs.com/xiaohu666/p/11419912.html
Copyright © 2011-2022 走看看