转载:
HIBERNATE的持久化对象加载策略。
延迟加载, 也就是用到的时候才去加载.这样可以提高一些性能.
Hibernate的lazy loading 采用了一个HibernateSession来管理session,它的逻辑是每进行一次数据库操作,就开新的session,操作完成后立即关闭该session。这样做的好处是可以严格关闭session,避免菜鸟级的错误,但是hibernate.org并不推荐这么做。因为这不适合lazy loading,也不适合跨方法的事务。
比如在我们的应用中,user->post形成一对多的映射,User中有一个包含post的List。
在User中,有多个属性:name,password,phone等,还有一个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进来,就打开一个session,response结束之后再关闭它,这样可以让session存在于整个请求周期中。
本文主要针对一对多情况下读取父类的子集合时,hibernate 的lazy属性在其中的影响进行总结。(以下代码运行在jdk1.5,jboss eclipse ide 1.5,hibernate 3.1环境下) 假设有:父类 Person (含有Set类型属性Address), 子类 Address(碰巧集合的名字和子类的名字都是Address,不要混淆了) Person.hbm.xml 主要片段: <id name="idx" column="idx" type="long" > <generator class="identity"> </generator> </id> <property name="age" type="int" update="true" insert="true" column="age" /> <property name="name" type="java.lang.String" update="true" insert="true" column="name" /> <set name="address" table="address" lazy="true" cascade="none" sort="unsorted" > <key > <column name="personidx" /> </key> <one-to-many class="com.abc.common.pojo.Address" />
</set> (1)在session 的周期内,无论lazy 设为true or false, 不会有任何限制。访问父子数据的代码如下所示 : //打开session session = HibernateUtil.currentSession();
PersonDAO dao = new PersonDAO(); Person person = null;
person = (Person)dao.findByPrimaryKey(4); Set addressSet = person.getAddress();
Address[] addressAry = new Address[addressSet.size()]; Address address = null ; addressSet.toArray(addressAry); for(int i=0 ;i<addressAry.length;i++){ ................ } //session关闭 session.close(); if (session.isOpen()){ HibernateUtil.closeSession(); }
(2)在session的周期外,访问父子数据的代码如下所示 : //打开session session = HibernateUtil.currentSession();
PersonDAO dao = new PersonDAO(); Person person = null;
person = (Person)dao.findByPrimaryKey(4); /********************** *留待后续处理 *********************/ session.close(); //session关闭之后才访问person的子集 Set addressSet = person.getAddress();
Address[] addressAry = new Address[addressSet.size()]; Address address = null ; addressSet.toArray(addressAry); for(int i=0 ;i<addressAry.length;i++){ ................ } if (session.isOpen()){ HibernateUtil.closeSession(); }
此时,上述代码的运行结果根据lazy的设置的不同而不同 lazy=false 结果:可以访问得到Person和Address的数据 lazy= true 根据代码的写法有不同 (1)代码其他处不做任何处理,则抛出异常 org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: 。。。。。。 (2)如果做一些处理如下,将上述那段代码中的"留待后续处理"换成以下代码 Hibernate.initialize(person.getAddress()); 则可以访问得到Person和Address的数据 实际编写时,不会象上述这样的写法,即将 Hibernate.initialize(person.getAddress());和person.getAddress()在同一个方法里面调用。他们往往出现在应用程序的不同层次中(前者出现在DAO层居多,而后者则出现在web层居多).
|