hibernate中的LazyLoad简介

HIBERNATE的持久化对象加载策略。
延迟加载, 也就是用到的时候才去加载.这样可以提高一些性能.
Hibernate
lazy loading 采用了一个 HibernateSession 来管理 session ,它的逻辑是每进行一次数据库操作,就开新的 session ,操作完成后立即关闭该 session 。这样做的好处是可以严格关闭 session ,避免菜鸟级的错误,但是 hibernate.org 并不推荐这么做。因为这不适合 lazy loading ,也不适合跨方法的事务。

比如在我们的应用中,user->post形成一对多的映射,User中有一个包含postList

User中,有多个属性:namepasswordphone等,还有一个List类型的posts。当我们对posts使用lazy laoding的时候,hibernate会在获得User对象的时候,仅仅返回name,password,phone等基本属性,当你访问posts的时候,它才会从数据库中提取posts需要的数据,这就是所谓lazy laoding。但是在我们的系统中,session是被立即关闭的,也就是在读取了name,password,phone等基本属性后,session已经close了,再进行lazy loaiding
就会有异常。
解决办法是在close session之前,调用Hibernate.initialize(user.getPosts()),告诉系统,user.getPosts()是需要lazy laoding的。但是这样做会破坏HibernateSession
类的封装.
后来采用所谓的OpenSessionInView模式,把session的周期交给servlet filter来管理,每当有request进来,就打开一个sessionresponse结束之后再关闭它,这样可以让session存在于整个请求周期中。


Hibernate中Lazy延迟加载
Hibernate有关one-to-one和many-to-one在查询中的父亲端lazy问题
Hibernate3在关联上有lazy这个属性,如果是Hibernate2,应该是设置outer-join="false",然后被关联的对象,在class那个地方设置lazy="true".首先,对于many-to-one的问题,可以在父亲端的class标签中设置lazy来解决,这样,在查询儿子的时候,不会发送多余的sql .
对于one-to-one,在hibernate2里面,由于one-to-one里面没有lazy的选项,所以只能通过设置outer-join="false"来解决。而hibernate3已经加入了lazy,所以不会有这个问题。
总体来说,如果你发现你查询儿子的时候,有多余的sql发送,那一定是你对hibernate的误用..

在hibernate 的one-to-many,many-to-one,many-to-many中,为了效率的提高,我们一般都采用lazy机制,但使用spring的getHibernateTemplate().save(Object)时,HibernateTemplate试图每次在execute之前去获得Session,执行完就力争关闭Session 。也就是说Hibernate的Lazy初始化1:n关系时,你必须保证是在同一个Session内部使用这个关系集合,不然Hiernate将抛出Failed to lazily initialize a collection - no session or session was closed的例外。


Hibernate中的对象的关联(association)的设置还是不够灵活,实际应用中有的地方需要lazy load,有的地方又不需要,其实还有的地方就根本不需要使用association。而在Hibernate中,只能在影射文件中设置一种方式,像我们这样的应用,我是不敢轻易使用open session in view的(慢点总比lock住要好),只能是要么不设置association,要么就是lazy=true的。以前的分类信息只用了一个many to one的关系,代价还可以忍受,但现在关系越来越复杂了,再多加几个的话,所要付出的performance,带宽等方面的代价恐怕就不能忽略了,即使使用cache提高一点performance,对带宽的浪费也还是不可原谅的

==========================================

Hibernate中lazy的设置

1.lazy是什么
    Hibernate中的lazy(默认true)网上很多人都把它叫懒人机制,主要是告诉Hibernate获取数据时在什么时候去读库;

2.lazy的影响
    就我做的例子看来。lazy只对session.Load和获取级联信息(1对1,1对多,多对多)时起作用;

3.Session读取信息的方式(Load和级联信息)
    3.1延迟加载(lazy=true)
        当我用Load或者是该bean中有级联对象的时候,执行Load的时候并不去读库,但Load还是会返回一个对象给你,但该对象中只有主键,读库是在你使用该对象的其他属性的时候去读的;
   3.2非延迟加载(lazy=false)
        在执行Load的时候就会去把库中的数据读取出来;

4.出问题的地方
    由于我们要保证Session要及时关闭,即Load完之后,我们要执行session.close操作;但是当lazy为真的时候,在Load的时候并是直接去读库,而是等使用里面属性的时候才去读库。那么到你打印信息的时候就会报session已经被关闭的错误。
    现在你是否要问,那直接把lazy设置成false不就可以了吗?现在看下面的例子吧:

5.例子(要调用Hibernate的show_sql为真)
    5.1lazy不设置,或者设置为true的时候(Load的情况)
        5.1.1代码
            Session session = HibernateSessionFactory.getSession();//获取session
          Tabuser tabuser = (Tabuser) session.load(Tabuser.class, new Long(1));//获取数据
            HibernateSessionFactory.closeSession();//关闭session
          System.out.println(tabuser.getUserid());
      System.out.println(tabuser.getUsername());
        5.1.2问题
            这时会提示第5行代码出错the owning Session was closed;
            这是由于session已经被你关闭了;
        5.1.3解决
            这时的解决办法有四种:
            a)设置class标签的lazy=false;(这种方式不推荐使用)
                b)在第三行之前加入Hibernate.initialize(tabuser);
                c)使用get方法(推荐使用这个,《get和load的区别》)
                d)使用spring(网上看到的:用filter[由于spring我还不懂,现在不讲这种方式,可能这种方式会更好])
    5.2一对多映射中set标签下lazy不设置,或者设置为true的时候(获取级联信息的情况1对多)
       5.2.1代码
            Session session = HibernateSessionFactory.getSession();
            Tabuser tabuser = (Tabuser) session.get(Tabuser.class, new Long(1));
          HibernateSessionFactory.closeSession();
            System.out.println(tabuser.getUserid());
            System.out.println(tabuser.getUsername());
            System.out.println(tabuser.getPostlist().iterator().next().getPostid());
        5.2.2问题
           这时第6行会报错no session or session was closed;
            这是由于session已经被你关闭了;
       5.2.3解决方法有三种:
            a)set标签下设置lazy=false;(这种方式不可行)
            b)在第三行之前加入Hibernate.initialize(tabuser.getPostlist());
            c)使用spring
        5.2.4为什么说设置lazy=false不可行
            由于你在set标签后设置lazy=false的时候,那么以后你再搜索数据的时候,Hibernate都会去获取其对应的set列表(那是否浪费掉非常多的资源,设置了这个值,可能会把整个数据库中与tabuser表有级联关系的数据全读出来[一条链子])
6.总结
    大家可以运行上面的例子,并注意观察打印信息及HQL显示的位置,即可推断出HQL是什么时候执行的

7.补充
    有涉及到延迟读取好像只有Load读取和级联信息
    如果获取信息用Query的话,则执行query.list的时候就已经读库了


你可能感兴趣的:(hibernate中的LazyLoad简介)