一.概述
我們先來談談檢索數據時的兩個問題:
1.不浪費內存 2.更好的檢索效率
以上說的問題都是我們想要避免的,接下來就引出了我們要討論的話題---------------hibernate檢索策略
二.hibernate檢索策略分為三種:
1.類級別的檢索策略
2.一對多和多對多檢索策略
3.多對一和一對一關聯的檢索策略
(1)類級別的檢索策略分為立即檢索和延遲檢索,默認為延遲檢索。
立即檢索:立即加載檢索方法指定的對象,立即發送SQL.
延遲檢索:延遲加載檢索方法指定的對象,在使用具體的對象時,再進行加載,發送SQL.
lazy有兩個取值:false(立即加載) 和 true(延遲加載)
討論一:當用get()方法檢索數據時,在類級別檢索策略不管是不是延遲加載都會立即檢索
接下來看看代碼實現是不是跟我說的一樣:
配置文件中:
測試類代碼:
@Test public void select1(){ Session session = HibernateUtil.currentSession(); Transaction tx = session.beginTransaction(); House house = session.get(House.class, 1); System.out.println("==========================="); // System.out.println(house.getType().getName()); tx.commit(); HibernateUtil.closeSession(); }
接下來看看測試的效果:
接下來我們把lazy設為true:
效果:
大家注意沒,測試類有一行代碼我是注釋掉的,為的就是讓我們很好的理解,如果我把下面的代碼放開是什么效果呢?大家要注意現在我們的查詢是get()方法:
我們得到的結果是一樣的,這樣就說明了當使用類級別檢索時,使用get()方法都會立即加載。
討論二:我們在來看看load()方法(也是類級別的檢索),我們只需要修改代碼即可:
@Test public void select1(){ Session session = HibernateUtil.currentSession(); Transaction tx = session.beginTransaction(); House house = session.load(House.class, 1); System.out.println("=========lazy:false=================="); //System.out.println(house.getType().getName()); tx.commit(); HibernateUtil.closeSession(); }
lazy:false時:
我們把lazy設為true時效果如下:
我們看到只打印了分割線,到這里我們可以看出get()和load()方法在類級別檢索時的區別,接下來我們看看當放開注釋的代碼時會發生什么呢?
我們可以很直觀的看出來,得到的結果不一樣,當延遲加載的情況下,當我們有后續操作時才會向數據庫發送SQL,查詢結果。而立即加載在我們有后續操作之前,已經先查詢了一道,然后再根據后續操作查詢結果。
通過以上我們做的測試,我們可以得出一個結論:
當類級別檢索時:get()方法不管延遲加載還是延遲加載都會先查詢一道,有后續操作再向數據庫發送SQL,得到結果。
load()方法:當是延遲加載的情況下,有后續操作才會向數據庫發送SQL,查詢結果。
當是立即加載的情況下,就和get()方法一樣,先查詢一道,有后續從操作在查詢。
總的來說,load()方法受類級別檢索策略影響,get()方法不受影響。
(2)一對多和多對多檢索策略
在映射文件中,用<set>元素來配置一對多和多對多關聯關系
lazy取值有:false(立即加載),true(延遲加載)和extra(加強延遲加載)
配置文件:
測試類代碼:
@Test
public void select(){ Session session = HibernateUtil.currentSession(); Transaction tx = session.beginTransaction(); House house = session.load(House.class, 1); System.out.println("==========lazy:false==================="); System.out.println(house.getClass()); // System.out.println(house.getTitle()); tx.commit(); HibernateUtil.closeSession(); }
先來看看當我們使用load()加載數據時,我們輸出的結果:
當lazy取值為false:
當lazy取值為true:
都沒有后續操作時,沒有不同。接下來我們看一下當有后續操作時(解開注釋的代碼),會發生什么?
lazy:true時:
lazy為false時:
我們可以明顯的看出這兩個的不同,延遲加載時發送了一條SQL,立即加載時發送了兩條SQL,延遲加載的后續操作是根據你的條件查詢的,立即加載根據你的條件查詢之后,如果有與之相關的表,也會進行兩表查詢。
get()方法獲取時,沒有后續操作:
lazy:true
lazy:false:
當有后續操作時,看看是什么情況?
lazy:true時,
lazy:false時,
由此可以看出,當使用get()方法時,不管有沒有后續操作,都會先向數據庫發送SQL語句,保存對象的信息,而且我們也看出來不管load()和get()在立即加載情況下,會向數據庫發送SQL,根據你查詢對象所關聯的表的個數來決定向數據庫發送幾條SQL語句,(我列舉的例子是發送兩條)。
當lazy取值為extra(加強延遲加載),接下來的測試,我們主要探討的是獲取集合的size()時有什么不同:
配置文件:
測試類代碼:
@Test public void select(){ Session session = HibernateUtil.currentSession(); Transaction tx = session.beginTransaction(); Users users = session.get(Users.class, 2); System.out.println("==========lazy:true==================="); System.out.println(users.getClass()); //System.out.println(users.getHouse().size()); tx.commit(); HibernateUtil.closeSession(); }
先來探討沒有后續操作時,get()和load()方法
get()方法:
load()方法:
當有后續操作時,get()和load()方法的結果:
get()方法:
load()方法:
當有后續操作時,get()和load()方法向數據庫索要數據的語句相同。不同的是get()方法不管有沒有后續操作都會向數據庫發送SQL,
而load()方法是在你用到它的屬性的時候才會向數據庫發送SQL。
最后看一下當取值為true 和 false時語句有什么不同?
在延遲加載的情況下:
get()方法獲取數據 load()方法獲取數據
在立即加載的情況下:
get()方法加載數據: load()方法加載數據:
這里寫的可能有點啰嗦了,但是總的一句話:
Extra:極其懶惰,只有訪問集合對象的屬性時才會加載,訪問集合本身的屬性時(例如,集合大小,生成count),不會立即加載。
最后來給大家總結一下:
類級別檢索策略:僅僅適用於load()加載
好了,就討論到這里吧,可能我寫的也不是太好,這就需要自己下來多多練習,熟練實踐.......