转自:http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=1840
首先我們來看看這個主題:
依這個主題所完成的例子,請將Hibernate的show_sql設定為true,當我們使用下面的程式時,觀看控制台所使用的SQL:
HibernateTest.javaimport onlyfun.caterpillar.*;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
import java.util.*;
public class HibernateTest {
public static void main(String[] args) throws HibernateException {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
List users = session.find("from User");
session.close();
sessionFactory.close();
}
}
SQL運作的例子如下:
Hibernate: select user0_.USER_ID as USER_ID, user0_.NAME as NAME from USER user0_
Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?
Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?
可以看到的,除了從USER表格中讀取資料之外,還向ADDRS表格讀取資料,預設上,Hibernate會將所有關聯到的物件,透過一連串的SQL語句讀取並載入資料,然而現在考慮一種情況,我們只是要取得所有USER的名稱,而不用取得它們的郵件位址,此時自動讀取相關聯的物件就是不必要的。
在Hibernate中,集合類的映射可以延遲初始(Lazy Initialization),也就是在真正索取該物件的資料時,才向資料庫查詢,就這個例子來說,就是我們在讀取User時,先不取得其中的 addrs屬性中之物件資料,由於只需要讀取User的name屬性,此時我們只要執行一次select即可,真正需要addrs的資料時,才向資料庫要求。
要使用Hibernate的延遲初始功能,只要在集合類映射時,加上lazy="true"即可,例如在我們的User.hbm.xml中的<set>中如下設定:
User.hbm.xml
<set name="addrs" table="ADDRS" lazy="true">
<key column="USER_ID"/>
<element type="string" column="ADDRESS" not-null="true"/>
</set>
我們來看看下面這個程式:
HibernateTest.javaimport onlyfun.caterpillar.*;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
import java.util.*;
public class HibernateTest {
public static void main(String[] args) throws HibernateException {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
List users = session.find("from User");
for (ListIterator iterator = users.listIterator(); iterator.hasNext(); ) {
User user = (User) iterator.next();
System.out.println(user.getName());
Object[] addrs = user.getAddrs().toArray();
for(int i = 0; i < addrs.length; i++) {
System.out.println("\taddress " + (i+1) + ": " + addrs[i]);
}
}
session.close();
sessionFactory.close();
}
}
在沒有使用延遲初始時,控制台會顯示以下的內容:
Hibernate: select user0_.USER_ID as USER_ID, user0_.NAME as NAME from USER user0_
Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?
Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?
caterpillar
address 1: caterpillar@caterpillar.onlyfun.net
address 2: justin@caterpillar.onlyfun.net
address 3: justin@fake.com
momor
address 1: momor@fake.com
address 2: momor@caterpillar.onlyfun.net
如果使用延遲初始,則會出現以下的內容:
Hibernate: select user0_.USER_ID as USER_ID, user0_.NAME as NAME from USER user0_
caterpillar
Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?
address 1: caterpillar@caterpillar.onlyfun.net
address 2: justin@caterpillar.onlyfun.net
address 3: justin@fake.com
momor
Hibernate: select addrs0_.USER_ID as USER_ID__, addrs0_.ADDRESS as ADDRESS__ from ADDRS addrs0_ where addrs0_.USER_ID=?
address 1: momor@fake.com
address 2: momor@caterpillar.onlyfun.net
請注意SQL語句出現的位置,在使用延遲初始功能前,會將所有相關聯到的資料一次查完,而使用了延遲初始之後,只有在真正需要addrs的資料時,才會使用SQL查詢相關資料。
Hibernate實現延遲初始功能的方法,是藉由實現一個代理物件(以Set來說,其實現的代理子類是 net.sf.hibernate.collection.Set),這個代理類實現了其所代理之物件之相關方法,每個方法的實現實際上是委托(delegate)真正的物件,查詢時載入的是代理物件,在真正呼叫物件的相關方法之前,不會去初始真正的物件來執行被呼叫的方法。
所以為了能使用延遲初始,您在使用集合映射時,在宣告時必須是集合類的介面,而不是具體的實現類(例如宣告時使用Set,而不是HashSet)。
使用延遲初始的一個問題是,由於在需要時才會去查詢資料庫,所以session不能關閉,如果在session關閉後,再去要求被關聯的物件,將會發生LazyInitializationException,像是:
Set addrs = user.getAddrs();
session.close();
// 下面這句會發生LazyInitializationException
Object[] addrs = user.getAddrs().toArray();
如果您使用了延遲初始,而在某些時候仍有需要在session關閉之後取得相關物件,則可以使用Hibernate.initialize()來先行載入相關物件,例如:
Hibernate.initialize(user.getAddrs());
session.close();
Set add = user.getAddrs();
Object[] addo = user.getAddrs().toArray();
延遲初始只是Hibernate在取得資料時的一種策略,目的是為了調節資料庫存取時的時機以取得一些效能,除了延遲初始之外,還有其它的策略來調整資料庫存取的方法與時機,這部份牽涉的討論範圍很大,有興趣的話,可以參考Hibernate in Action的4.4.5。
分享到:
相关推荐
Hibernate 的 lazyload 在FLEX中的解决方法例子 用的是gilead 因为LIB包太大上传很慢所以被我删掉了。
hibernate 中的lazy属性的使用
NULL 博文链接:https://xuwoool.iteye.com/blog/1306207
Dwr+Hibernate的Lazy问题 解决了Hibernate延迟加载失效问题
NULL 博文链接:https://quicker.iteye.com/blog/662613
Hibernate延时加载与lazy机制.docHibernate延时加载与lazy机制.doc
博文链接:https://llying.iteye.com/blog/221699
Hibernate fetch lazy cascade inverse 关键字
博文链接:https://llying.iteye.com/blog/221700
NULL 博文链接:https://afuer.iteye.com/blog/1508008
Hibernate 的延迟加载(lazy load)是一个被广泛使用的技术。这种延迟加载保证了应用只有在需要时才去数据库中抓取相应的记录。通过延迟加载技术可以避免过多、过早地加载数据表里的数据,从而降低应用的内存开销。...
Hibernate中Cascade和inverse的区别,讲解的很详细
001 Hibernate 简介(开源 O/R 映射框架) 002 第一个 Hibernate 示例 003 hibernate 主要接口介绍 004 持久对象的生命周期介绍 005 query 接口初步 006 开源 O/R 映射框架内容回顾 007 Hibernate 基本映射标签和属性...
Hibernate环境搭建 Hibernate主要接口 Hibernate主要映射 Hibernate的lazy、fetch、cascade等策略 Hibernate性能优化
Lazy
延迟初始化(延迟加载)(Lazy Initialization) 6.6. 集合排序(Sorted Collections) 6.7. 使用<idbag><br>6.8. 双向关联(Bidirectional Associations) 6.9. 三重关联(Ternary Associations) 6.10....
hibernate映射lazy策略hibernate查询语言hql
Lazy_Theta_star是在 Theta_star上的进一步改进,Theta_star是当节点加入open表时和当前点的父节点进行比较g值是否更小,对一些不必要的节点计算浪费了时间,而Lazy_Theta_star则是在弹出open表后进行比较,减少了...
17.1.4 关于本章范例程序 17.1.5 使用别名 17.1.6 多态查询 17.1.7 对查询结果排序 17.1.8 分页查询 17.1.9 检索单个对象(uniqueResult()方法) 17.1.10 按主键逐个处理查询结果(iterate()方法) ...
In this article I want to discuss the lazy loading mechanism provided by NHibernate. It is recommended for maximum flexibility to define all relations in your domain as lazy loadable. This is the ...