Hibernate(十四)Hibernate三種檢索方式詳解


Hibernate檢索機制中主要分爲三種,他們各自有各自的好處和缺點,他主要分爲以下三種:

1.立即檢索策略 

2.延遲檢索策略 

3.左外連接檢索策略 

立即加載:首先我們來看一下立即加載

                                             

List customerLists=session.createQuery("from Customer as c").list();


      運行以上方法時,Hibernate將先查詢CUSTOMERS表中所有的記錄,然後根據每條記錄的ID,到ORDERS表中查詢有參照關係的記錄,Hibernate將依次執行以下select語句: 

select * from CUSTOMERS; 
select * from ORDERS where CUSTOMER_ID=1; 
select * from ORDERS where CUSTOMER_ID=2; 
select * from ORDERS where CUSTOMER_ID=3; 
select * from ORDERS where CUSTOMER_ID=4;

立即檢索缺點:

          select語句的數目太多,需要頻繁的訪問數據庫,會影響檢索性能。如果需要查詢n個Customer對象,那麼必須執行n+1次select查詢語 句。這種檢索策略沒有利用SQL的連接查詢功能,例如以上5條select語句完全可以通過以下1條select語句來完成: 

select * from CUSTOMERS left outer join ORDERS 
on CUSTOMERS.ID=ORDERS.CUSTOMER_ID


      以上select語句使用了SQL的左外連接查詢功能,能夠在一條select語句中查詢出CUSTOMERS表的所有記錄,以及匹配的ORDERS表的記錄。 在應用邏輯只需要訪問Customer對象,而不需要訪問Order對象的場合,加載Order對象完全是多餘的操作,這些多餘的Order對象白白浪費了許多內存空間。 

延遲加載:我們在一起來看一下延遲加載

一對多,對於<set>元素,應該優先考慮使用延遲檢索策略: 

<set name="orders" inverse="true" lazy="true" >


此時運行: 

Customer customer=(Customer)session.get 
(Customer.class,new Long(1));


僅立即檢索Customer對象,執行以下select語句: 

select * from CUSTOMERS where ID=1; 

Customer對象的orders變量引用集合代理類實例,當應用程序第一次訪問 它,例如調用customer.getOrders().iterator()方法時,Hibernate會初始化這個集合代理類實例,在初始化過程中到 數據庫中檢索所有與Customer關聯的Order對象,執行以下select語句: 

select * from ORDERS where CUSTOMER_ID=1; 

訪問沒有被初始化的遊離狀態的集合代理類實例

Session session=sessionFactory.openSession(); 
tx = session.beginTransaction(); 
Customer customer=(Customer)session.get(Customer.class,new Long(1)); 
tx.commit(); 
session.close(); 
//拋出異常 
Iterator orderIterator=customer.getOrders().iterator(); 
執行以上代碼,會拋出以下異常: 
ERROR LazyInitializer:63 - Exception initializing proxy


優點 

由應用程序決定需要加載哪些對象,可以避免執行多餘的select語句,以及避免加載應用程序不需要訪問的對象。因此能提高檢索性能,並且能節省內存空間。 

缺點 

應用程序如果希望訪問遊離狀態的代理類實例,必須保證它在持久化狀態時已經被初始化。 

適用範圍 

一對多或者多對多關聯。 

應用程序不需要立即訪問或者根本不會訪問的對象。 

左外連接檢索策略

默認情況下,多對一關聯使用左外連接檢索策略。 

如果把Order.hbm.xml文件的<many-to-one>元素的outer-join屬性設爲true,總是使用左外連接檢索策略。 

對於以下程序代碼: 

Order order=(Order)session.get(Order.class,new Long(1));

在運行session.get()方法時,Hibernate執行以下select語句: 

select * from ORDERS left outer join CUSTOMERS 
on ORDERS.CUSTOMER_ID=CUSTOMERS.ID where ORDERS.ID=1

左外連接查詢優點 

1.對應用程序完全透明,不管對象處於持久化狀態,還是遊離狀態,應用程序都可以方便的從一個對象導航到與它關聯的對象。 

2.使用了外連接,select語句數目少。 

左外連接查詢缺點 

1.可能會加載應用程序不需要訪問的對象,白白浪費許多內存空間。 

2.複雜的數據庫表連接也會影響檢索性能。 

左外連接查詢適用範圍 

1.多對一或者一對一關聯。 

2.應用程序需要立即訪問的對象。 

3.數據庫系統具有良好的表連接性能 

在映射文件中設定的檢索策略是固定的,要麼爲延遲檢索,要麼爲立即檢索,要麼爲外連接 檢索。 但應用邏輯是多種多樣的,有些情況下需要延遲檢索,而有些情況下需要外連接檢索。 Hibernate允許在應用程序中覆蓋映射文件中設定的檢索 策略,由應用程序在運行時決定檢索對象圖的深度。 

以下Session的方法都用於檢索OID爲1的Customer對象: 

session.createQuery("from Customer as c where c.id=1"); 
session.createQuery("from Customer as c left join fetch c.orders 
where c.id=1");


在執行第一個方法時,將使用映射文件配置的檢索策略。 

在執行第二個方法時,在HQL語句中顯式指定左外連接檢索關聯的Order對象,因 此會覆蓋映射文件配置的檢索策略。不管在Customer.hbm.xml文件中<set>元素的lazy屬性是true還是 false,Hibernate都會執行以下select語句: 

select * from CUSTOMERS left outer join ORDERS 
on CUSTOMERS.ID =ORDERS.CUSTOMER_ID 
where CUSTOMERS.ID=1;


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章