假設現在有Book和Category兩張表,表的關系為雙向的一對多,表結構如下:
假設現在我想查詢id為2的那本書的書名,使用session.get(...)方法:
1 Session session=HibernateUtil.getSession();
2 Book book =(Book) session.get(Book.class,2);
3 System.out.println(book.getName());
當執行完第二行代碼,還未執行第三行時,控制臺已經打印出了sql語句,執行第三行時打印出書名"斗破蒼穹".
而如果使用session.load(..)查詢時:
1 Session session=HibernateUtil.getSession();
2 Book book =(Book) session.load(Book.class,1);
3 System.out.println(book.getName());
當執行完第二行代碼還未執行第三行時,控制臺什么都沒有打印,執行第三行時,控制臺打印出sql語句和書名"斗破蒼穹".
看出get和load的區別了嗎?
實際上,當使用get方法查詢時,程序立即去訪問數據庫(實際上是先去一級緩存session中查詢,沒有發現的話再去二級緩存,再沒有的話才去訪問數據庫),得到id=2的Book,并且打印出sql語句,而是用load方法查詢時,load并未立即去訪問數據庫,他先是返回了一個Book的代理對象,當你真正要用到Book中信息時,才去訪問數據庫.load支持延遲加載,get不支持延遲加載,當然如果設置了lazy=false,get和load都會直接去訪問數據庫,都變成即時加載.
get/load方法還有一個很重要的區別就是:
load方式檢索不到的話會拋出org.hibernate.ObjectNotFoundException異常
get方法檢索不到的話會返回null
這就引出了即時加載和延時加載的概念,通俗的說,即時加載,就是立即去數據庫查找,延遲加載,就是真正需要的時候才去數據庫查找,這類似于單例模式中的懶漢式和餓漢式的加載方式.
假設我現在想通過查詢Book,來得到Book所對應的Category,如果設置為即時加載,當加載Book時,會自動加載Category,如果設置為延遲加載,則加載Book時,不會加載Category,只有當第一次調用getCategory(),時,才去執行sql語句,加載Category.
一般來說,延遲加載要比即時加載節省資源,但是如果處理不當,延遲加載容易拋出延遲加載異常(LazyInitializationException).這是因為延遲加載時,只有第一次調用getCategory()時才會加載Category數據,如果這時候數據庫連接已經關閉了,就會因為無法加載數據而拋出異常.
在*.hbm.xml中可以設置加載方式,class標簽中可以設置:lazy="true",打開延遲加載,默認就是lazy="true".
在set/bag標簽下,默認也是lazy="true",支持延遲加載,也叫懶加載.
單端關聯(many_to_one或者one_to_one)上也可以設置lazy="true".默認也是true支持懶加載.
下面是網絡上一段關于get和load方法的詳細異同,寫的不錯,貼在這里:
一、get和load方法都是根據id去獲得對應數據的,但是獲得機制不同:如果使用get方法,hibernate會去確認該id對應的數據是否存在,它首先會去session中去查詢(session緩存其實就hibernate的一級緩存),如果沒有,再去二級緩存中去查詢,如果再沒有,就去數據庫中查詢,仍然沒有找到的話,就返回null
而使用load方法的話,hibernate會認定該id對應的數據一定存在,它也會先去session緩存中去查找,如果沒有找到,hibernate會根據lazy屬性值來確定是否使用延遲加載。如果lazy=‘true’ ,就使用延遲加載,返回該代理對象,等到真正訪問到該對象的屬性時才會去二級緩存中查詢,如果沒有,再去數據庫中查詢,如果還沒有,就拋出org.hibernate.ObjectNotFoundException異常。如果lazy='false' 則不使用延遲加載,這是load的訪問機制就和get一樣了。
二、對于load和get方法返回類型:雖然好多書中都這么說:“get()永遠只返回實體類”,但實際上這是不正確的,get方法如果在 session緩存中找到了該id對應的對象,如果剛好該對象前面是被代理過的,如被load方法使用過,或者被其他關聯對象延遲加載過,那么返回的還是 原先的代理對象,而不是實體類對象,如果該代理對象還沒有加載實體數據(就是id以外的其他屬性數據),那么它會查詢二級緩存或者數據庫來加載數據,但是 返回的還是代理對象,只不過已經加載了實體數據。
?
?
?
抓取策略:
在hibernate的官方文檔中對于抓取策略,是這么定義的:
當應用程序需要在(hibernate實體對象圖的)關聯關系間進行對象導航的時候,hibernate如何獲取關聯對象的策略.
fetch="select":當查詢關聯對象通過select語句去查詢,Select語句的發出時機,是根據lazy的值來確定的,如果lazy="false",那么在獲取對象時,就會發出一條select語句,將關聯對象查詢出來,就是說,我們在查詢Book信息的時候會自動把Category的數據也查詢出來,但如果lazy="true",那么只有在獲取關聯對象的時候才會發出select語句去查詢.
fetch="join":當查詢Book信息時,會通過outer join把關聯的對象Category一起查詢出來,這個時候lazy無效,所有數據會立即查詢出來.
fetch="subselect":如果要查詢關聯集合的內容,會查詢之前已經查詢出來的所有關聯集合的內容,<category對應了多張Book,如果查詢了"玄幻類","武俠類",那么在使用"玄幻類"和"武俠類"對應的集合對象("所對應的書籍信息"),會將他們的書籍信息一并查詢出來,
?