`
艳沐石
  • 浏览: 37036 次
  • 性别: Icon_minigender_1
  • 来自: 天津
文章分类
社区版块
存档分类
最新评论

关于延迟加载(lazy)和强制加载(Hibernate.initialize(Object proxy) )

阅读更多
文章参考:http://www.cnblogs.com/kelin1314/archive/2009/11/13/1602778.html
延迟加载(Lazy Loading)

为了避免一些情况下,关联关系所带来的无谓的性能开销。Hibernate引入了延迟加载的概念。如,示例中user对象在加载的时候,会同时读取其所关联的多个地址(address)对象,
对于需要对address进行操作的应用逻辑而言,关联数据的自动加载机制的确非常有效。但是,如果我们只是想要获得user的性别(sex)属性,而不关心user的地址(address)
信息,那么自动加载address的特性就显得多余,并且造成了极大的性能浪费。为了获得user 的性别属性,我们可能还要同时从数据库中读取数条无用的地址数据,这导致了大量无谓的系统开销。

延迟加载特性的出现,正是为了解决这个问题。所谓延迟加载,就是在需要数据的时候,才真正执行数据加载操作。

对于我们这里的user对象的加载过程,也就意味着,加载user对象时只针对其本身的属性, 而当我们需要获取user对象所关联的address信息时(如执行user.getAddresses时),才
真正从数据库中加载address数据并返回。
尝试执行以下代码:

Criteria criteria = session.createCriteria(TUser.class);

criteria.add(Expression.eq("name","Erica"));
List userList = criteria.list();
TUser user =(TUser)userList.get(0);

System.out.println("User name => "+user.getName());
Set hset = user.getAddresses();

session.close();//关闭Session

TAddress addr = (TAddress)hset.toArray()[0];
System.out.println(addr.getAddress());

运行时抛出异常:
LazyInitializationException - Failed to lazily initialize a collection - no session or session was closed

如果我们稍做调整,将session.close放在代码末尾,则不会发生这样的问题。这意味着,只有我们实际加载user 关联的address时,Hibernate 才试图通过
session从数据库中加载实际的数据集,而由于我们读取address之前已经关闭了session,所以报出session已关闭的错误。

这里有个问题,如果我们采用了延迟加载机制,但希望在一些情况下,实现非延迟加载时的功能,也就是说,我们希望在Session关闭后,依然允许操作user的addresses
属性。如,为了向View层提供数据,我们必须提供一个完整的User对象,包含其所关联的address信息,而这个User对象必须在Session关闭之后仍然可以使用。

Hibernate.initialize方法可以通过强制加载关联对象实现这一功能:

Hibernate.initialize(user.getAddresses());
session.close();
//通过Hibernate.initialize方法强制读取数据
//addresses对象即可脱离session进行操作

Set hset= user.getAddresses();
TAddress addr = (TAddress)hset.toArray()[0];
System.out.println(addr.getAddress());

为了实现透明化的延迟加载机制,hibernate进行了大量努力。其中包括JDK Collection接口的独立实现。
如果我们尝试用HashSet强行转化Hibernate返回的Set 型对象:

Set hset = (HashSet)user.getAddresses();

就会在运行期得到一个java.lang.ClassCastException, 实际上,此时返回的是一个Hibernate的特定Set实现“net.sf.hibernate.collection.Set”对象,而非
传统意义上的JDK Set实现。这也正是我们为什么在编写POJO时,必须用JDKCollection 接口(如Set,Map), 而非特定的JDKCollection 实现类(如HashSet、HashMap)申明Collection属性的原因。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics