1. 程式人生 > >梳理hibernate篇-原理及快取機制

梳理hibernate篇-原理及快取機制

Hibernate工作原理  本文出自: http://www.cnblogs.com/bile/p/4030575.html  現在我們知道了一個概念Hibernate Session,只有處於Session管理下的POJO才具有持久化操作能力。當應用程式對於處於Session管理下的POJO例項執行操作時,Hibernate將這種面向物件的操作轉換成了持久化操作能力。

HIbernate簡要的體系結構如下圖所示: 這裡寫圖片描述  通過上圖能夠發現HIbernate需要一個hibernate.properties檔案,該檔案用於配置Hibernate和資料庫連線的資訊。還需要一個XML檔案,該對映檔案確定了持久化類和資料表、資料列之間的想對應關係。

除了使用hibernate.properties檔案,還可以採用另一種形式的配置檔案: *.cfg.xml檔案。在實際應用中,採用XML配置檔案的方式更加廣泛,兩種配置檔案的實質是一樣的。

    Hibernate的持久化解決方案將使用者從赤裸裸的JDBC訪問中釋放出來,使用者無需關注底層的JDBC操作,而是以面向物件的方式進行持久層操作。底層資料連線的獲得、資料訪問的實現、事務控制都無需使用者關心。這是一種“全面解決”的體系結構方案,將應用層從底層的JDBC/JTA API中抽象出來。通過配置檔案來管理底層的JDBC連線,讓Hibernate解決持久化訪問的實現。這種“全面解決”方案的體系結構圖如圖所示:
  • 1

這裡寫圖片描述  針對以上的Hibernate全面解決方案架構圖:

  (1)SessionFactory:這是Hibernate的關鍵物件,它是單個數據庫對映關係經過編譯後的記憶體映象,它也是執行緒安全的。它是生成Session的工廠,本身要應用到ConnectionProvider,該物件可以在程序和叢集的級別上,為那些事務之間可以重用的資料提供可選的二級快取。

  (2)Session:它是應用程式和持久儲存層之間互動操作的一個單執行緒物件。它也是Hibernate持久化操作的關鍵物件,所有的持久化物件必須在Session的管理下才能夠進行持久化操作。此物件的生存週期很短,其隱藏了JDBC連線,也是Transaction 的工廠。Session物件有一個一級快取,現實執行Flush之前,所有的持久化操作的資料都在快取中Session物件處。

  (3)持久化物件:系統建立的POJO例項一旦與特定Session關聯,並對應資料表的指定記錄,那該物件就處於持久化狀態,這一系列的物件都被稱為持久化物件。程式中對持久化物件的修改,都將自動轉換為持久層的修改。持久化物件完全可以是普通的Java Beans/POJO,唯一的特殊性是它們正與Session關聯著。

  (4)瞬態物件和脫管物件:系統進行new關鍵字進行建立的Java 例項,沒有Session 相關聯,此時處於瞬態。瞬態例項可能是在被應用程式例項化後,尚未進行持久化的物件。如果一個曾今持久化過的例項,但因為Session的關閉而轉換為脫管狀態。

  (5)事務(Transaction):代表一次原子操作,它具有資料庫事務的概念。但它通過抽象,將應用程式從底層的具體的JDBC、JTA和CORBA事務中隔離開。在某些情況下,一個Session 之內可能包含多個Transaction物件。雖然事務操作是可選的,但是所有的持久化操作都應該在事務管理下進行,即使是隻讀操作。

  (6)連線提供者(ConnectionProvider):它是生成JDBC的連線的工廠,同時具備連線池的作用。他通過抽象將底層的DataSource和DriverManager隔離開。這個物件無需應用程式直接訪問,僅在應用程式需要擴充套件時使用。

  (7)事務工廠(TransactionFactory):他是生成Transaction物件例項的工廠。該物件也無需應用程式的直接訪問。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Hibernate進行持久化操作離不開SessionFactory物件,這個物件是整個資料庫對映關係經過編譯後的記憶體映象,該物件的openSession()方法可開啟Session物件。SessionFactory對想是由Configuration物件產生。

每個Hibernate配置檔案對應一個configuration物件。在極端情況下,不使用任何配置檔案,也可以建立Configuration物件。

一. 建立Configuration物件

    org.hibernate.cfg.Configuration例項代表一個應用程式到SQL資料庫的對映配置,Configuration提供了一個buildSessionFactory()方法,該方法可以產生一個不可變的SessionFactory物件。

    你可以直接例項化Configuration來獲取一個例項,併為它指定一個Hibernate對映檔案,如果對映檔案在類載入路徑中,則可以使用addResource()方法來新增對映定義檔案。那麼現在的問題就是如何建立Configuration物件呢?
  • 1
  • 2
  • 3

隨著Hibernate 所使用的配置檔案的不同,建立Configuration物件的方式也不相同。通常有幾種配置Hibernate的方式:

第一種是使用hibernate.properties檔案作為配置檔案。

第二種是使用hibernate.cfg.xml檔案作為配置檔案。

第三種是不使用任何的配置檔案,以編碼方式來建立Configuration物件。

請注意:Configuration物件的唯一作用就是建立SessionFactory例項,所以它才被設計成為啟動期間物件,而一旦SessionFactory物件建立完成,它就被丟棄了。

  1. 使用hibernateproperties作為配置檔案

    對於hibernate.properties作為配置檔案的方式,比較適合於初學者。因為初學者往往很難記住該配置檔案的格式,以及需要配置哪些屬性。在Hibernate釋出包的etc路徑下,提供了一個hibernate.properties檔案,該檔案列出了Hibernate 的所有屬性。每個配置段都給出了大致的註釋,使用者只要取消所需配置段的註釋,就可以快速配置Hibernate和資料庫的連結此處給出使用hibernate.properties檔案建立Configuration物件的方法。
    
    • 1

//例項化configuration物件  Configuration cfg = new Configuration()  //多次呼叫addResource()方法,新增對映檔案  .addResource(“Item.hbm.xml”)  .addResource(“Bid.hbm.xml”);  檢視hibernate.properties檔案發現,該檔案沒有提供Hibernate對映檔案的方式。因此使用hibernate.properties檔案來作為配置檔案時,必須使用Configuration的.addResource()方法,使用該方法來新增對映檔案。

注意:正如上面的程式碼所示,使用hibernate.properties檔案配置Hibernate的屬性固然簡單,但是因為要手動新增對映檔案,當對映檔案極其多時,這是一件非常催人淚下的事情。這也就是在實際開發中,不常使用hibernate.properties檔案作為配置檔案的原因。

    當然還有另一種新增配置檔案的策略,因為對映檔案和持久化類是一一對應的,可以通過Configuration物件來新增持久化類,讓Hibernate自己來搜尋對映檔案。
  • 1

//例項化configuration物件  Configuration cfg = new Configuration)  //多次呼叫addClass()方法,直接新增持久化類  .addClass(ppp.Item.class)  .addClass(ppp.BId.class);

  1. 使用hibernate.cfg.xml作為配置檔案

     前面已經看到使用hibernate.properties作為配置檔案的情形。因為hibernate.cfg.xml中已經添加了hibernate的對映檔案,採用這種配置檔案建立configuration物件例項由以下程式碼實現:
    
    • 1

//例項化configuration物件  Configuration cfg = new Configuration()  //configure()方法將會負責載入hibernate.cfg.xml檔案  .configure()  需要注意的是:在通過new關鍵字建立Configuration物件之後,不要忘記呼叫configure()方法。

二. hibernate.properties和hiberntae.cfg.xml檔案

    如果使用etc路徑下的hibernate.properties檔案作為配置檔案的模板,修改此模板檔案作為Hibernate配置檔案,這種方式的確是快速進入Hibernate開發的方法。但是對於實際開發,通常會使用hibernate.cfg.xml檔案作為配置檔案。
  • 1

深入對比hibernate.properties和hibernate.cfg.xml檔案後看如下的hibernate.properties的一個配置屬性:

//指定資料庫的方言  hibernate.dialect org.hibernate.dialect.MySQLDialect  上面的一行程式碼是典型的Properties檔案的的格式,前面的key為hibernate.dialect , 後面的value是為org.hibernate.dialect.MySQLDialect。

接下來我們再來檢視hibernate.cfg.xml檔案中的相對應的配置程式碼:

org.hibernate.dialect.MySQLDialect  同樣指定了Hibernate的Dialect 屬性是org.hibernate.dialect.MySQLDialect 。對比兩種格式的檔案,可以發現雖然格式不同但其實質完全一樣。

Hibernate的工作原理及Hibernate的快取機制  本文出自: http://blog.sina.com.cn/s/blog_3fe0488301008nmt.html  工作原理  1.Hibernate 的初始化.  讀取Hibernate 的配置資訊-〉建立Session Factory  1)建立Configeration類的例項。  它的構造方法:將配置資訊(Hibernate config.xml)讀入到記憶體。  一個Configeration 例項代表Hibernate 所有Java類到Sql資料庫對映的集合。  2)建立SessionFactory例項  把Configeration 物件中的所有配置資訊拷貝到SessionFactory的快取中。  SessionFactory的例項代表一個數據庫儲存員源,建立後不再與Configeration 物件關聯。  快取(cache):指Java物件的屬性(通常是一些集合型別的屬性--佔用記憶體空間。  SessionFactory的快取中:Hibernate 配置資訊。O\R對映元資料。  快取-大:重量級物件 小:輕量級物件  3)呼叫SessionFactory建立Session的方法  1】使用者自行提供JDBC連線。  Connection con=dataSource.getConnection();  Session s=sessionFactory.openSession(con);  2】讓SessionFactory提供連線  Session s=sessionFactory.openSession();  4)通過Session 介面提供的各種方法來操縱資料庫訪問。  Hibernate 的快取體系  一級快取:  Session 有一個內建的快取,其中存放了被當前工作單元載入的物件。  每個Session 都有自己獨立的快取,且只能被當前工作單元訪問。  二級快取:  SessionFactory的外接的可插拔的快取外掛。其中的資料可被多個Session共享訪問。  SessionFactory的內建快取:存放了對映元資料,預定義的Sql語句。  Hibernate 中Java物件的狀態  1.臨時狀態 (transient)  特徵:  1】不處於Session 快取中  2】資料庫中沒有物件記錄  Java如何進入臨時狀態  1】通過new語句剛建立一個物件時  2】當呼叫Session 的delete()方法,從Session 快取中刪除一個物件時。  2.持久化狀態(persisted)  特徵:  1】處於Session 快取中  2】持久化物件資料庫中設有物件記錄  3】Session 在特定時刻會保持二者同步  Java如何進入持久化狀態  1】Session 的save()把臨時-》持久化狀態  2】Session 的load(),get()方法返回的物件  3】Session 的find()返回的list集合中存放的物件  4】Session 的update(),saveOrupdate()使遊離-》持久化  3.遊離狀態(detached)  特徵:  1】不再位於Session 快取中  2】遊離物件由持久化狀態轉變而來,資料庫中可能還有對應記錄。  Java如何進入持久化狀態-》遊離狀態  1】Session 的close()方法  2】Session 的evict()方法,從快取中刪除一個物件。提高效能。少用。  快取機制詳解:  快取是介於應用程式和物理資料來源之間,其作用是為了降低應用程式對物理資料來源訪問的頻次,從而提高了應用的執行效能。快取內的資料是對物理資料來源中的資料的複製,應用程式在執行時從快取讀寫資料,在特定的時刻或事件會同步快取和物理資料來源的資料。    快取的介質一般是記憶體,所以讀寫速度很快。但如果快取中存放的資料量非常大時,也會用硬碟作為快取介質。快取的實現不僅僅要考慮儲存的介質,還要考慮到管理快取的併發訪問和快取資料的生命週期。    Hibernate的快取包括Session的快取和SessionFactory的快取,其中SessionFactory的快取又可以分為兩類:內建快取和外接快取。Session的快取是內建的,不能被解除安裝,也被稱為Hibernate的第一級快取。SessionFactory的內建快取和Session的快取在實現方式上比較相似,前者是SessionFactory物件的一些集合屬性包含的資料,後者是指Session的一些集合屬性包含的資料。SessionFactory的內建快取中存放了對映元資料和預定義SQL語句,對映元資料是對映檔案中資料的拷貝,而預定義SQL語句是在Hibernate初始化階段根據對映元資料推匯出來,SessionFactory的內建快取是隻讀的,應用程式不能修改快取中的對映元資料和預定義SQL語句,因此SessionFactory不需要進行內建快取與對映檔案的同步。SessionFactory的外接快取是一個可配置的外掛。在預設情況下,SessionFactory不會啟用這個外掛。外接快取的資料是資料庫資料的拷貝,外接快取的介質可以是記憶體或者硬碟。SessionFactory的外接快取也被稱為Hibernate的第二級快取。    Hibernate的這兩級快取都位於持久化層,存放的都是資料庫資料的拷貝,那麼它們之間的區別是什麼呢?為了理解二者的區別,需要深入理解持久化層的快取的兩個特性:快取的範圍和快取的併發訪問策略。  持久化層的快取的範圍    快取的範圍決定了快取的生命週期以及可以被誰訪問。快取的範圍分為三類。    1 事務範圍:快取只能被當前事務訪問。快取的生命週期依賴於事務的生命週期,當事務結束時,快取也就結束生命週期。在此範圍下,快取的介質是記憶體。事務可以是資料庫事務或者應用事務,每個事務都有獨自的快取,快取內的資料通常採用相互關聯的的物件形式。    2 程序範圍:快取被程序內的所有事務共享。這些事務有可能是併發訪問快取,因此必須對快取採取必要的事務隔離機制。快取的生命週期依賴於程序的生命週期,程序結束時,快取也就結束了生命週期。程序範圍的快取可能會存放大量的資料,所以存放的介質可以是記憶體或硬碟。快取內的資料既可以是相互關聯的物件形式也可以是物件的鬆散資料形式。鬆散的物件資料形式有點類似於物件的序列化資料,但是物件分解為鬆散的演算法比物件序列化的演算法要求更快。    3 叢集範圍:在叢集環境中,快取被一個機器或者多個機器的程序共享。快取中的資料被複制到叢集環境中的每個程序節點,程序間通過遠端通訊來保證快取中的資料的一致性,快取中的資料通常採用物件的鬆散資料形式。    對大多數應用來說,應該慎重地考慮是否需要使用叢集範圍的快取,因為訪問的速度不一定會比直接訪問資料庫資料的速度快多少。    持久化層可以提供多種範圍的快取。如果在事務範圍的快取中沒有查到相應的資料,還可以到程序範圍或叢集範圍的快取內查詢,如果還是沒有查到,那麼只有到資料庫中查詢。事務範圍的快取是持久化層的第一級快取,通常它是必需的;程序範圍或叢集範圍的快取是持久化層的第二級快取,通常是可選的。  持久化層的快取的併發訪問策略    當多個併發的事務同時訪問持久化層的快取的相同資料時,會引起併發問題,必須採用必要的事務隔離措施。    在程序範圍或叢集範圍的快取,即第二級快取,會出現併發問題。因此可以設定以下四種類型的併發訪問策略,每一種策略對應一種事務隔離級別。    事務型:僅僅在受管理環境中適用。它提供了Repeatable Read事務隔離級別。對於經常被讀但很少修改的資料,可以採用這種隔離型別,因為它可以防止髒讀和不可重複讀這類的併發問題。    讀寫型:提供了Read Committed事務隔離級別。僅僅在非叢集的環境中適用。對於經常被讀但很少修改的資料,可以採用這種隔離型別,因為它可以防止髒讀這類的併發問題。    非嚴格讀寫型:不保證快取與資料庫中資料的一致性。如果存在兩個事務同時訪問快取中相同資料的可能,必須為該資料配置一個很短的資料過期時間,從而儘量避免髒讀。對於極少被修改,並且允許偶爾髒讀的資料,可以採用這種併發訪問策略。    只讀型:對於從來不會修改的資料,如參考資料,可以使用這種併發訪問策略。    事務型併發訪問策略是事務隔離級別最高,只讀型的隔離級別最低。事務隔離級別越高,併發效能就越低。  什麼樣的資料適合存放到第二級快取中?  1 很少被修改的資料  2 不是很重要的資料,允許出現偶爾併發的資料  3 不會被併發訪問的資料  4 參考資料  不適合存放到第二級快取的資料?  1 經常被修改的資料  2 財務資料,絕對不允許出現併發  3 與其他應用共享的資料。  Hibernate的二級快取    如前所述,Hibernate提供了兩級快取,第一級是Session的快取。由於Session物件的生命週期通常對應一個數據庫事務或者一個應用事務,因此它的快取是事務範圍的快取。第一級快取是必需的,不允許而且事實上也無法比卸除。在第一級快取中,持久化類的每個例項都具有唯一的OID。    第二級快取是一個可插拔的的快取外掛,它是由SessionFactory負責管理。由於SessionFactory物件的生命週期和應用程式的整個過程對應,因此第二級快取是程序範圍或者叢集範圍的快取。這個快取中存放的物件的鬆散資料。第二級物件有可能出現併發問題,因此需要採用適當的併發訪問策略,該策略為被快取的資料提供了事務隔離級別。快取介面卡用於把具體的快取實現軟體與Hibernate整合。第二級快取是可選的,可以在每個類或每個集合的粒度上配置第二級快取。  Hibernate的二級快取策略的一般過程如下:  1) 條件查詢的時候,總是發出一條select * from table_name where …. (選擇所有欄位)這樣的SQL語句查詢資料庫,一次獲得所有的資料物件。  2) 把獲得的所有資料物件根據ID放入到第二級快取中。  3) 當Hibernate根據ID訪問資料物件的時候,首先從Session一級快取中查;查不到,如果配置了二級快取,那麼從二級快取中查;查不到,再查詢資料庫,把結果按照ID放入到快取。  4) 刪除、更新、增加資料的時候,同時更新快取。    Hibernate的二級快取策略,是針對於ID查詢的快取策略,對於條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的Query快取。  Hibernate的Query快取策略的過程如下:  1) Hibernate首先根據這些資訊組成一個Query Key,Query Key包括條件查詢的請求一般資訊:SQL, SQL需要的引數,記錄範圍(起始位置rowStart,最大記錄個數maxRows),等。  2) Hibernate根據這個Query Key到Query快取中查詢對應的結果列表。如果存在,那麼返回這個結果列表;如果不存在,查詢資料庫,獲取結果列表,把整個結果列表根據Query Key放入到Query快取中。  3) Query Key中的SQL涉及到一些表名,如果這些表的任何資料發生修改、刪除、增加等操作,這些相關的Query Key都要從快取中清空