[NHibernate]延遲加載


目錄

寫在前面

文檔與系列文章

延遲加載

一個例子

總結

寫在前面

上篇文章介紹了多對多關系的關聯查詢的sql,HQL,Criteria查詢的三種方式。本篇文章將介紹nhibernate中的延遲加載方式,延遲加載按個人理解也可以叫做按需要加載(Loading-on-demand)。

文檔與系列文章

[Nhibernate]體系結構

[NHibernate]ISessionFactory配置

[NHibernate]持久化類(Persistent Classes)

[NHibernate]O/R Mapping基礎

[NHibernate]集合類(Collections)映射 

[NHibernate]關聯映射

[NHibernate]Parent/Child

[NHibernate]緩存(NHibernate.Caches)

[NHibernate]NHibernate.Tool.hbm2net

[NHibernate]Nullables

[NHibernate]Nhibernate如何映射sqlserver中image字段

[NHibernate]基本配置與測試 

[NHibernate]HQL查詢 

[NHibernate]條件查詢Criteria Query

[NHibernate]增刪改操作

[NHibernate]事務

[NHibernate]並發控制

[NHibernate]組件之依賴對象

[NHibernate]一對多關系(級聯刪除,級聯添加)

[NHibernate]一對多關系(關聯查詢)

[NHibernate]多對多關系(關聯查詢)

延遲加載

延遲加載(Lazy Load)是(也成為懶加載)Hibernate3關聯關系對象默認的加載方式,延遲加載機制是為了避免一些無謂的性能開銷而提出來的,所謂延遲加載就是當在真正需要數據的時候,才真正執行數據加載操作。可以簡單理解為,只有在使用的時候,才會發出sql語句進行查詢。

延遲加載的有效期是在session打開的情況下,當session關閉后,會報異常。當調用load方法加載對象時,返回代理對象,等到真正用到對象的內容時才發出sql語句。

Hibernate2實現延遲加載有2種方式:1實體對象,2集合。

Hibernate3中又引入了一種新的加載方式:3屬性的延遲加載。

一般使用load的方法來實現延遲加載,在實現無限級聯動使用延遲加載效率比較好。

——百度百科(java,hibernate)

上面是java中對hibernate的延遲加載的描述,說的比我好多了。

記住三點:1,為了避免無謂的性能開銷。2,需要時才真正加載數據。3,使用了代理。 

一個例子

一對多關系

默認延遲加載

采用懶加載的方式根據客戶id得到客戶信息

 1         /// <summary>
 2         /// 采用懶加載的方式根據客戶id得到客戶信息
 3         /// </summary>
 4         /// <param name="customerID"></param>
 5         /// <returns></returns>
 6         public Customer GetCustomerbyLazyLoad(Guid customerID)
 7         {
 8             //獲得ISession實例
 9             ISession session = NHibernateHelper.GetSession();
10             Customer customer = session.Get<Customer>(customerID);
11             return customer;
12         }

 測試用代碼,如圖所示,此時數據已經加載出來了

使用SQL Profile監控生成的sql語句,截圖如下

 

你會發現,此時只生成了查詢customer的sql語句,nhibernate默認是使用延遲加載的,在前面的文章中,並沒在映射文件中設置節點的lazy屬性。

當展開customer的屬性Orders時或者調試向下移動的時候,會執行查詢,你會看到如下的sql語句

延遲加載並關閉Session

 1         /// <summary>
 2         /// 采用using釋放session,懶加載的方式根據客戶id得到客戶信息
 3         /// </summary>
 4         /// <param name="customerID"></param>
 5         /// <returns></returns>
 6         public Customer GetCustomerbyLazyLoadUsing(Guid customerID)
 7         {
 8             //獲得ISession實例
 9             using(ISession session = NHibernateHelper.GetSession())
10             {
11                 Customer customer = session.Get<Customer>(customerID);
12                 return customer;
13             }
14         }

測試,當視圖展開customer的orders屬性,或者往下執行獲得order集合時出錯。

延遲加載,需要的時候再去加載,因為此時session已經關閉,沒有去查詢的通道了,結果是“此路不通”的提示。

多對多關系

默認延遲加載

這里采用多對多關系那篇文章中舉的 Order和Product的例子。

 1         /// <summary>
 2         /// 多對多關系,延遲加載訂單產品
 3         /// </summary>
 4         /// <returns></returns>
 5         public Order GetOrderByLazyLoad(Guid orderId)
 6         {
 7             try
 8             {
 9                 var session = NHibernateHelper.GetSession();
10                 return session.Get<Wolfy.Shop.Domain.Entities.Order>(orderId);
11             }
12             catch (Exception)
13             {
14                 throw;
15             }
16         }

進行測試,在查詢的時候只有Order表的數據(這個地方,有Order數據的sql,猜測在一對多查詢的時候,沒有出現查詢Customer的sql語句,很有可能是因為緩存的問題造成,因為經常使用Cusomer那條數據進行測試。)

展開Order的屬性

當展開Order的屬性,回去查詢order下的所有的Product,此時生成的sql如下:

延遲加載並關閉Session

 1         /// <summary>
 2         /// 多對多關系,延遲加載訂單產品
 3         /// </summary>
 4         /// <returns></returns>
 5         public Order GetOrderByLazyLoadUsing(Guid orderId)
 6         {
 7             //session使用后即釋放
 8             using (var session = NHibernateHelper.GetSession())
 9             { return session.Get<Wolfy.Shop.Domain.Entities.Order>(orderId); }
10         }

測試

此時生成的sql語句

如果此時展開Products,同樣會出現上面的異常

通過上面的比較一對多和多對多的默認延遲加載和關閉session后的情況類似。

N+1次select查詢問題

如果Order下有很多個Product,而我們就想需要的時候才去加載其中某些Product的信息,如果采用立即加載的方式,勢必產生多個sql語句,例如第一次查詢得到所有的Order對象,然后根據orderid去查詢得到所有的產品。

測試,多對多延遲加載訂單和訂單下單價大於6666的產品

 1        protected void btnMany2Many_Click(object sender, EventArgs e)
 2         {
 3             Business.OrderBusiness orderBusiness = new Business.OrderBusiness();
 4             Order order = orderBusiness.GetOrderByLazyLoad(new Guid("78A53F67-A293-48A1-BBE2-86FED77342FA"));
 5             decimal sum = 0;
 6             foreach (var item in order.Products)
 7             {
 8                 if (item.Price >= 6666)
 9                 {
10                     sum += item.Price;
11                 }
12             }
13             Response.Write(sum.ToString());
14         }

生成的sql語句

延遲加載,可以解決select N+1的問題,比如你查詢一個訂單還有訂單下的Product,勢必會產生多條sql語句,先是查詢order的sql語句,然后是查詢product的sql語句,就會頻繁的查詢數據庫,造成性能方面的壓力,而采用延遲加載,通過上面生成的sql語句你會發現,使用left out join 將關聯的表拼接起來,只生成了一條sql。

總結

本篇文章介紹了Nhibernate在延遲加載方面的內容,Nhibernate在使用過程中延遲加載方式是默認的。對延遲加載的定義,需要再慢慢的體會。

延遲加載(Lazy Load)是(也成為懶加載)Hibernate3關聯關系對象默認的加載方式,延遲加載機制是為了避免一些無謂的性能開銷而提出來的,所謂延遲加載就是當在真正需要數據的時候,才真正執行數據加載操作。可以簡單理解為,只有在使用的時候,才會發出sql語句進行查詢。

延遲加載的有效期是在session打開的情況下,當session關閉后,會報異常。當調用load方法加載對象時,返回代理對象,等到真正用到對象的內容時才發出sql語句。

Hibernate2實現延遲加載有2種方式:1實體對象,2集合。

Hibernate3中又引入了一種新的加載方式:3屬性的延遲加載。

一般使用load的方法來實現延遲加載,在實現無限級聯動使用延遲加載效率比較好。

——百度百科(java,hibernate)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM