Session.load/get方法都可以根據指定的實體類和id從數據庫讀取記錄,並返回與之對應的實體對象。
其區別在於: 若是未能發現符合條件的記錄,get方法返回null,而load方法會拋出一個ObjectNotFoundException。 Load方法可返回實體的代理類實例,而get方法永遠直接返回實體類。數據庫
load方法能夠充分利用內部緩存和二級緩存中的現有數據,而get方法則僅僅在內部緩存中進行數據查找,如沒有發現對應數據,將越過二級緩存,直接調用SQL完成數據讀取。緩存
Session在加載實體對象時,將通過的過程: 首先,Hibernate中維持了兩級緩存。第一級緩存由Session實例維護,其中保持了Session當前全部關聯實體的數據,也稱爲內部緩存。而第二級緩存則存在於SessionFactory層次,由當前全部由本SessionFactory構造的Session實例共享。出於性能考慮,避免無謂的數據庫訪問,Session在調用數據庫查詢功能以前,會先在緩存中進行查詢。首先在第一級緩存中,經過實體類型和id進行查找,若是第一級緩存查找命中,且數據狀態合法,則直接返回。
以後,Session會在當前「NonExists(把無效的條件寫成一個黑名單,既然無效,那麼也不必再查下去)」記錄中進行查找,若是「NonExists」記錄中存在一樣的查詢條件,則返回null。「NonExists」記錄了當前Session實例在以前全部查詢操做中,未能查詢到有效數據的查詢條件(至關於一個查詢黑名單列表)。如此一來,若是Session中一個無效的查詢條件重複出現,便可迅速做出判斷,從而得到最佳的性能表現。
對於load方法而言,若是內部緩存中未發現有效數據,則查詢第二級緩存,若是第二級緩存命中,則返回。session
如在緩存中未發現有效數據,則發起數據庫查詢操做(Select SQL),如通過查詢未發現對應記錄,則將這次查詢的信息在「NonExists」中加以記錄,並返回null。性能
根據映射配置和Select SQL獲得的ResultSet,建立對應的數據對象。 將其數據對象歸入當前Session實體管理容器(一級緩存)。 執行Interceptor.onLoad方法(若是有對應的Interceptor)。 將數據對象歸入二級緩存。 若是數據對象實現了LifeCycle接口,則調用數據對象的onLoad方法。 返回數據對象。
/** *//** * load()方法的執行順序以下: * a):首先經過id在session緩存中查找對象,若是存在此id的對象,直接將其返回 * b):在二級緩存中查找,找到後將 其返回。 * c):若是在session緩存和二級緩存中都找不到此對象,則從數據庫中加載有此ID的對象 * 所以load()方法並不老是致使SQL語句,只有緩存中無此數據時,才向數據庫發送SQL! */
/** *//** * 與get()的區別: * 1:在當即加載對象(當hibernate在從數據庫中取得數據組裝好一個對象後 * 會當即再從數據庫取得數據此對象所關聯的對象)時,若是對象存在, * load()和get()方法沒有區別,均可以取得已初始化的對象;但若是當對 * 象不存在且是當即加載時,使用get()方法則返回null,而使用load()則 * 拋出一個異常。所以使用load()方法時,要確認查詢的主鍵ID必定是存在 * 的,從這一點講它沒有get方便! * 2:在延遲加載對象(Hibernate從數據庫中取得數據組裝好一個對象後, * 不會當即再從數據庫取得數據組裝此對象所關聯的對象,而是等到須要時, * 都會從數據庫取得數據組裝此對象關聯的對象)時,get()方法仍然使用 * 當即加載的方式發送SQL語句,並獲得已初始化的對象,而load()方法則 * 根本不發送SQL語句,它返回一個代理對象,直到這個對象被訪問時才被 * 初始化。 */
get()----不支持LAZY
load()----支持LAZY
load和get一共是2個區別 先講第一個 延遲加載 load是true而get是false 意 思就是 load採用的是延遲加載的方式 而get不是,hibernate思想是 既然這個方法支持延遲加載 他就認爲這個對象必定在數據庫存在,在你 聲明 TFaq tfag2=(TFaq)sess.load(TFaq.class, 300); 這句時候,hibernate就幹了一件事 1.查詢session緩存 2.緩存中沒有這個對象 就建立個代理 由於延遲加載須要代理來執行 因此就建立了個代理 ok 到此爲止 這句話就幹了個這個 並無去數據庫交互查詢 當你使用這個對象 好比tfag2.getTfRtitle()或get方法時候 這個時候 hibernate就去查詢二級緩存和數據庫,數據庫沒有這條數據 就拋出異常 整個load方法調用結束 load沒什麼神奇 這就是他幹過全部的事情
load方法講完了 我在講一下get方法工做原理 由於hibernate規定get方法不能使用延遲加載 因此和load仍是不同的 TFaq tfag2=(TFaq)sess.get(TFaq.class, 300); 在建立這條語句時候 咱們看看hibernate幹了哪些事 1.get方法首先查詢session緩存 (session緩存就是hibernate的一級緩存 這個概念你們應該清楚吧 ) 2.get方法若是在session緩存中找到了該id對應的對象,若是恰好該對象前面是被代理過的,如被load方法使用過,或者被其餘關聯對象延遲加載過,那麼返回的仍是原先的代理對象,而不是實體類對象。 3.若是該代理對象尚未加載實體數據(就是id之外的其餘屬性數據),那麼它會查詢二級緩存或者數據庫來加載數據,可是返回的仍是代理對象,只不過已經加載了實體數據。 (這個代理實際就是空的對象 並無去數據庫查詢獲得的 咱們叫代理對象,若是 去數據庫查詢了 返回到了這個對象 咱們叫實體對象 就是這個對象真實存在)
我在總結性一句話這2者區別 get方法首先查詢session緩存,沒有的話查詢二級緩存,最後查詢數據庫;反而load方法建立時首先查詢session緩存,沒有就建立代理,實際使用數據時才查詢二級緩存和數據庫
----我測試過:
在使用session.get方法後若是把session關閉的話,也會出現懶加載異常。
那麼只有在manytoone標籤裏配置 lazy="false"時異常纔會解決。
也就是說上面轉載的第3條不是那麼正確:返回該代理對象不錯,可是若是該對象沒有加載實體數據,那麼也會在用到時纔會加載,即不會當即查詢數據庫或者二級緩存,那麼你如今把session關閉,這個對行啊沒有加載實體數據----纔會出現懶加載異常。測試
裝載自:http://blog.csdn.net/houjiyu243042162/article/details/27243029.net