天天看點

Hibernate -------- 常用的接口和類

目錄:

-----configuration

-----sessionFactory

-----session

(session 和factory有個緩存的差别:請參考:

https://blog.csdn.net/qq_36098284/article/details/80086519)

-----transaction

1 configuration

Hibernate -------- 常用的接口和類

預設使用config.configure()的時候,讀取的配置檔案就是hibernate.cfg.xml。

但是configure()的方法有好幾個,可以用于配置自定義的XML檔案。

Hibernate -------- 常用的接口和類

如果更改了.cfg.xml檔案的名字,那麼相應的config處也要更改。

Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類

2 SessionFactory

Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類

是以每次要建立一個session的時候,隻需要調用這個工廠類的方法OpenSession即可。

當然還可以把closeSession()方法寫進去。

3 Session

複習下,session有三種狀态 參考:https://blog.csdn.net/qq_36098284/article/details/80072932

Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類

3.1 get方法詳解:

Session.load/get方法均可以根據指定的實體類和id從資料庫讀取記錄,并傳回與之對應的實體對象。

get與load的差別:

1.如果未能發現符合條件的記錄,get方法傳回null,而load方法會抛出一個ObjectNotFoundException。

2.load方法可傳回實體的代理類執行個體,而get方法永遠直接傳回實體類。

3.load方法可以充分利用内部緩存和二級緩存中的現有資料,而get方法則僅僅在内部緩存中進行資料查找,如沒有發現對應資料,将越過二級緩存,直接調用SQL完成資料讀取。

Session在加載實體對象時,将經過的過程:

       首先,Hibernate中維持了兩級緩存。第一級緩存由Session執行個體維護,其中保持了Session目前所有關聯實體的資料,也稱為内部緩存。而第二級緩存則存在于SessionFactory層次,由目前所有由本SessionFactory構造的Session執行個體共享。出于性能考慮,避免無謂的資料庫通路,Session在調用資料庫查詢功能之前,會先在緩存中進行查詢。首先在第一級緩存中,通過實體類型和id進行查找,如果第一級緩存查找命中,且資料狀态合法,則直接傳回。

      之後,Session會在目前“NonExists(把無效的條件寫成一個黑名單,既然無效,那麼也沒必要再查下去)”記錄中進行查找,如果“NonExists”記錄中存在同樣的查詢條件,則傳回null。“NonExists”記錄了目前Session執行個體在之前所有查詢操作中,未能查詢到有效資料的查詢條件(相當于一個查詢黑名單清單)。如此一來,如果Session中一個無效的查詢條件重複出現,即可迅速作出判斷,進而獲得最佳的性能表現。 

       對于load方法而言,如果内部緩存中未發現有效資料,則查詢第二級緩存,如果第二級緩存命中,則傳回。

如在緩存中未發現有效資料,則發起資料庫查詢操作(Select SQL),如經過查詢未發現對應記錄,則将此次查詢的資訊在“NonExists”中加以記錄,并傳回null。

根據映射配置和Select SQL得到的ResultSet,建立對應的資料對象。

将其資料對象納入目前Session實體管理容器(一級緩存)。

執行Interceptor.onLoad方法(如果有對應的Interceptor)。

将資料對象納入二級緩存。

如果資料對象實作了LifeCycle接口,則調用資料對象的onLoad方法。

傳回資料對象。

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緩存,沒有就建立代理,實際使用資料時才查詢二級緩存和資料庫

參考:https://blog.csdn.net/houjiyu243042162/article/details/27243029

舉例:

Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類

3.2 save方法詳解

3.2.1.save(): 把一個臨時對象加入到緩存中,使它變成持久化對象

-->選用映射檔案指定的主鍵生成器為持久化對象配置設定唯一的OID

-->計劃一條insert語句,把參數對象目前的屬性值組裝到insert語句中,但是save()方法并不立即執行SQL insert語句,隻有當Session清理緩存時候才會執行。

-->如果在save()方法之後,又修改了持久化對象的屬性,會使得Session在清理緩存的時候額外執行SQL update語句。

注意:save()方法是用來持久化一個臨時對象的!

  如果将一個持久化對象傳給save()方法将不會執行任何操作,多餘的步驟

  如果将一個遊離态對象傳給save()方法,session會将它當作臨時對象來處理,再次向資料庫中插入一條記錄,不符合業務需求!

3.2.2舉例

Hibernate -------- 常用的接口和類
Hibernate -------- 常用的接口和類

3.3 update方法詳解

3.3.2.update():把Customer對象重新加入到Session緩存中,使之變為持久化對象。

   --->計劃一條update語句,隻有在清理緩存的時候才會執行,并且在執行的時候才會把參數對象中的屬性值組裝到update語句中。

注意:update()是将一個遊離對象轉變為持久化對象的。

  隻要通過update()方法使遊離對象被一個session關聯,即使沒有修改參數對象的任何屬性,Session在清理緩存的時候也會執行由update方法計劃的Update語句。

3.3.3舉例

相當于select。insert。

Hibernate -------- 常用的接口和類

3.4.saveOrUpdate詳解

同時包含了save()與update()方法的功能。

如果傳入的參數是臨時對象,調用save方法。

如果參入參數是遊離對象,調用update()方法。

如果傳入的是持久化對象,直接傳回。

3.5.evict與clear詳解

5.1.evict():從緩存中清除參數指定的持久化對象。

  适用場合:不希望Session繼續按照該對象的狀态改變來同步更新資料庫。

    在批量更新或批量删除的場合,當更新或者删除一個對象後,及時釋放該對象占用的記憶體。當然批量操作優先考慮JDBC.

5.2.clear():清空緩存中所有持久化對象。

3.6.delete詳解

用于從資料庫中删除與參數對象對應的記錄。

如果傳入的參數是持久化對象,Session就計劃執行一個delete語句,如果傳入的參數是遊離對象,先使遊離對象被Session關聯,使它變為持久化對象,然後計劃一個delete語句,在清理緩存的時候執行。

相當于 select 。drop 

Hibernate -------- 常用的接口和類

3.7.queryAll詳解

相當于select。

Hibernate -------- 常用的接口和類

4. Transation 

(此處是對于事務的一個基本了解,深入了解在另一個文章中,參考:https://blog.csdn.net/qq_36098284/article/details/80094923)

Hibernate -------- 常用的接口和類

隻要try中代碼出現問題進入到catch中,那麼就不會執行commit(),而是去執行rollback()代碼。就相當于回到了session = null 建立那一步。

而且标準的寫法也是必須要有try-catch的。否則會出現資料的錯誤。

Hibernate -------- 常用的接口和類

事物復原的解釋:

最近在用做hibernate做項目,一直不明白session.beginTransaction().commit() 和 session.beginTransaction().rollback(); 有什麼差別

一組業務整體處理的行為叫一個事務。這一組的業務都能成功處理,我們就可以把這個事務送出來儲存你已做的行為結果。但如果一組中有任何的差錯出現的話,我們就認為這事務不成功,需要復原來撤消之前的操作。
舉例:你去銀行轉賬,轉賬我們有兩步吧,從你賬戶中取出錢再往他賬戶中加錢。那這兩步銀行是必須要確定正确無誤的進行的。要被看做成一個事務。其中任何一步出錯就算是轉賬失敗,但可能你這時是已經從你賬戶中扣了錢了,又沒往他賬戶裡加錢?怎麼辦算了?你不肯吧。是以銀行會事務復原,不儲存你剛才的操作,即恢複到你沒轉賬之前的狀态。      
Hibernate -------- 常用的接口和類

參考:https://www.cnblogs.com/demongao/p/6053853.html

參考:https://blog.csdn.net/qq_33642117/article/details/52008152