複製鏈接
請複製以下鏈接發送給好友

Hibernate

(開放源代碼的對象關係映射框架)

鎖定
Hibernate是一個開放源代碼對象關係映射框架,它對JDBC進行了非常輕量級的對象封裝,它將POJO與數據庫表建立映射關係,是一個全自動的orm框架,hibernate可以自動生成SQL語句,自動執行,使得Java程序員可以隨心所欲的使用對象編程思維來操縱數據庫。 Hibernate可以應用在任何使用JDBC的場合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web應用中使用,最具革命意義的是,Hibernate可以在應用EJBJavaEE架構中取代CMP,完成數據持久化的重任。
中文名
對象關係映射框架
外文名
Hibernate
典型應用
EJB的J2EE架構中取代CMP
屬    性
開放源代碼的對象關係映射框架
作    用
數據庫與界面之間的橋樑
關鍵技術
數據持久化

Hibernate簡介

Hibernate作為數據庫與界面之間的橋樑,需要面向對象思想操縱對象。對象可能是普通JavaBeans/POJO。應用程序通過抽象將應用從底層事務隔離開。使用底層的API或Transaction對象完成輕量級框架提供一級緩存和二級緩存。Hibernate直接提供相關支持,底層驅動可以隨意切換數據庫,快速簡潔。使業務層與具體數據庫分開,只針對Hibernate 進行開發,完成數據和對象的持久化。針對不同的數據庫形成不同的SQL 查詢語句,降低數據庫之間遷移的成本。Hibernate支持多種緩存機制,Hibernate適配MS SQLSERVER、ORACLE、SQL、H2、Access和Mysql等多種數據庫。
Hibernate用反射機制實現持久化對象操作,實現與IDE(Integrated Development Environment)的耦合度。Hibernate使用數據庫和配置信息為應用程序提供持久化服務。從配置文件中讀取數據庫相關參數,將持久化類和數據表對應使用。用Hibernate API對象持久化,利用映像信息將持久化操作翻譯為SQL語句進行查詢。
Hibernate框架技術最關鍵是數據持久化,是將數據保存到持久層的過程。持久層的數據在掉電後也不會丟失的數據。持久層是基於Hibernate技術的檢索系統開發的基本。系統結構層次模型有三個階段。
整個過程首先實現應用層和數據層。數據層保存持久化數據,應用層接收輸入的數據。然後通過MVC 模式實現業務邏輯與表示層的分開。表示層和用户實現交互,業務邏輯層處理數據持久化操作。將第二階段業務邏輯層的功能部署拆分後,業務邏輯層完成核心業務邏輯處理,持久層完成對象持久化。降低業務邏輯層複雜度的同時將數據持久化讓其他組件完成。 [1] 

Hibernate發展歷程

2001年,澳大利亞墨爾本一位名為Gavin King的27歲的程序員,上街買了一本SQL編程的書,他厭倦了實體bean,認為自己可以開發出一個符合對象關係映射理論,並且真正好用的Java持久化層框架,因此他需要先學習一下SQL。這一年的11月,Hibernate的第一個版本發佈了。
2002年,已經有人開始關注和使用Hibernate了。
2003年9月,Hibernate開發團隊進入JBoss公司,開始全職開發Hibernate,從這個時候開始Hibernate得到了突飛猛進的普及和發展。
2004年,整個Java社區開始從實體bean向Hibernate轉移,特別是在Rod Johnson的著作《Expert One-on-One J2EE Development without EJB》出版後,由於這本書以紮實的理論、充分的論據和詳實的論述否定了EJB,提出了輕量級敏捷開發理念之後,以Hibernate和Spring為代表的輕量級開源框架開始成為Java世界的主流和事實標準。在2004年Sun領導的J2EE5.0標準制定當中的持久化框架標準正式以Hibernate為藍本。
2006年,J2EE5.0標準正式發佈以後,持久化框架標準Java Persistent API(簡稱JPA)基本上是參考Hibernate實現的,而Hibernate在3.2版本開始,已經完全兼容JPA標準。 [2] 

Hibernate編程開發

Hibernate編程環境

Hibernate是一個以LGPL(Lesser GNU Public License)許可證形式發佈的開源項目。在Hibernate官網上有下載Hibernate包的説明。Hibernate包以源代碼或者二進制的形式提供。 [2] 

Hibernate編程工具

Hibernate Hibernate
Eclipse:一個開放源代碼的、基於Java的可擴展開發平台
NetBeans開放源碼的Java集成開發環境,適用於各種客户機和Web應用。
IntelliJ IDEA:在代碼自動提示、代碼分析等方面的具有很好的功能。
MyEclipse:由Genuitec公司開發的一款商業化軟件,是應用比較廣泛的Java應用程序集成開發環境。 [3] 
EditPlus:如果正確配置Java的編譯器Javac”以及解釋器“Java”後,可直接使用EditPlus編譯執行Java程序。

Hibernate語言特點

  • 將對數據庫的操作轉換為對Java對象的操作,從而簡化開發。通過修改一個“持久化”對象的屬性從而修改數據庫表中對應的記錄數據。
  • 提供線程和進程兩個級別的緩存提升應用程序性能。
  • 有豐富的映射方式將Java對象之間的關係轉換為數據庫表之間的關係。
  • 屏蔽不同數據庫實現之間的差異。在Hibernate中只需要通過“方言”的形式指定當前使用的數據庫,就可以根據底層數據庫的實際情況生成適合的SQL語句。
  • 非侵入式:Hibernate不要求持久化類實現任何接口或繼承任何類,POJO即可。

Hibernate核心API

Hibernate的API一共有6個,分別為:Session、SessionFactory、Transaction、Query、Criteria和Configuration。通過這些接口,可以對持久化對象進行存取、事務控制。
Session
Session接口負責執行被持久化對象的CRUD操作(CRUD的任務是完成與數據庫的交流,包含了很多常見的SQL語句)。但需要注意的是Session對象是非線程安全的。同時,Hibernate的session不同於JSP應用中的HttpSession。這裏當使用session這個術語時,其實指的是Hibernate中的session,而以後會將HttpSession對象稱為用户session。
SessionFactory
SessionFactory接口負責初始化Hibernate。它充當數據存儲源的代理,並負責創建Session對象。這裏用到了工廠模式。需要注意的是SessionFactory並不是輕量級的,因為一般情況下,一個項目通常只需要一個SessionFactory就夠,當需要操作多個數據庫時,可以為每個數據庫指定一個SessionFactory。
Transaction
Transaction 接口是一個可選的API,可以選擇不使用這個接口,取而代之的是Hibernate 的設計者自己寫的底層事務處理代碼。 Transaction 接口是對實際事務實現的一個抽象,這些實現包括JDBC的事務、JTA 中的UserTransaction、甚至可以是CORBA 事務。之所以這樣設計是能讓開發者能夠使用一個統一事務的操作界面,使得自己的項目可以在不同的環境和容器之間方便地移植。
Query
Query接口讓你方便地對數據庫及持久對象進行查詢,它可以有兩種表達方式:HQL語言或本地數據庫的SQL語句。Query經常被用來綁定查詢參數、限制查詢記錄數量,並最終執行查詢操作。
Criteria
Criteria接口與Query接口非常類似,允許創建並執行面向對象的標準化查詢。值得注意的是Criteria接口也是輕量級的,它不能在Session之外使用。
Configuration
Configuration 類的作用是對Hibernate 進行配置,以及對它進行啓動。在Hibernate 的啓動過程中,Configuration 類的實例首先定位映射文檔的位置,讀取這些配置,然後創建一個SessionFactory對象。雖然Configuration 類在整個Hibernate 項目中只扮演着一個很小的角色,但它是啓動hibernate 時所遇到的第一個對象。

Hibernate回調接口

當⼀個對象發生了特定的事件,例如對象被保存,刪除,更新和裝載時,Hibernate應用可以通過回調接口來響應這⼀事件,做相應的操作,主要有兩類實現方式: [4] 
1)持久化類實現LifeCycle和Validatabale接口。這種方式使Hibernate 接口滲透到了持久化類中,會影響持久化類的可移植性 [4] 
2)Interceptor接口,應用程序可以定義專門的攔截器實現類,由它負責事件的響應,這種方式持久化類不會受到影響。 [4] 

Hibernate可擴展點

1)定製主鍵的生成策略,IdentifierGenarator接口 [4] 
2)定製本地SQL方言,Dialect抽象類 [4] 
3)定製緩存機制,Cache和CacheProvider接口 [4] 
4)定製JDBC連接管理,ConnectionProvider接口 [4] 
5)定製事務管理,TransactionFactory,Transaction,TransactionManagerLookup接口 [4] 
6)定製ORM策略,classPersister接口及子接口 [4] 
7)定製屬性訪問策略,PropertyAccessor接口 [4] 
8)創建代理,ProxyFactory接口 [4] 
9)定製客户化映射關係,UserType和CompositeUserType接口 [4] 

Hibernate版本

Hibernate版本更新速度很快,有多個階段性的版本:Hibernate3、Hibernate4、Hibernate5、Hibernate ORM 5.2.12.Final Released。Hibernate2系列的最高版本是Hibernate2.1.8,Hibernate3系列的最高版本是hibernate-distribution-3.6.10.Final-dist版,但使用較多且較穩定的版本是Hibernate 3.1.3或Hibernate 3.1.2。
另外,自Hibernate3發佈以來,其產品線愈加成熟,相繼出現了Hibernate註釋、Hibernate實體管理器、Hibernate插件工具等一系列產品套件。在方便程序員使用Hibernate進行應用程序的開發的同時,也逐漸增強了Hibernate產品線的實力。Hibernate已經出現了4.0以及5.0的版本

Hibernate主鍵介紹

Assigned
Assigned方式由用户生成主鍵值,並且要在save()之前指定否則會拋出異常
特點:主鍵的生成值完全由用户決定,與底層數據庫無關。用户需要維護主鍵值,在調用session.save()之前要指定主鍵值。
Hilo
Hibernate相關書籍 Hibernate相關書籍
Hilo使用高低位算法生成主鍵,高低位算法使用一個高位值和一個低位值,然後把算法得到的兩個值拼接起來作為數據庫中的唯一主鍵。Hilo方式需要額外的數據庫表和字段提供高位值來源。默認情況下使用的表是
hibernate_unique_key,默認字段叫作next_hi。next_hi必須有一條記錄否則會出現錯誤。
特點:需要額外的數據庫表的支持,能保證同一個數據庫中主鍵的唯一性,但不能保證多個數據庫之間主鍵的唯一性。Hilo主鍵生成方式由Hibernate 維護,所以Hilo方式與底層數據庫無關,但不應該手動修改hi/lo算法使用的表的值,否則會引起主鍵重複的異常。
Increment
Increment方式對主鍵值採取自動增長的方式生成新的主鍵值,但要求底層數據庫的主鍵類型為long,int等數值型。主鍵按數值順序遞增,增量為1。
/*特點:由Hibernate本身維護,適用於所有的數據庫,不適合多進程併發更新數據庫,適合單一進程訪問數據庫。不能用於羣集環境。*/
Identity
Hibernate相關書籍 Hibernate相關書籍
Identity方式根據底層數據庫,來支持自動增長,不同的數據庫用不同的主鍵增長方式。
特點:與底層數據庫有關,要求數據庫支持Identity,如MySQl中是auto_increment, SQL Server 中是Identity,支持的數據庫有MySql、SQL Server、DB2、Sybase和HypersonicSQL。 Identity無需Hibernate和用户的干涉,使用較為方便,但不便於在不同的數據庫之間移植程序。
Sequence
Sequence需要底層數據庫支持Sequence方式,例如Oracle數據庫
特點:需要底層數據庫的支持序列,支持序列的數據庫有DB2、PostgreSql、Oracle、SAPDb等在不同數據庫之間移植程序,特別從支持序列的數據庫移植到不支持序列的數據庫需要修改配置文件
Native
Native主鍵生成方式會根據不同的底層數據庫自動選擇Identity、Sequence、Hilo主鍵生成方式
特點:根據不同的底層數據庫採用不同的主鍵生成方式。由於Hibernate會根據底層數據庫採用不同的映射方式,因此便於程序移植,項目中如果用到多個數據庫時,可以使用這種方式。
UUID使用128位UUID算法生成主鍵,能夠保證網絡環境下的主鍵唯一性,也就能夠保證在不同數據庫及不同服務器下主鍵的唯一性。特點:能夠保證數據庫中的主鍵唯一性,生成的主鍵佔用比較多的存貯空間
Foreign GUID
Foreign用於一對一關係中。GUID主鍵生成方式使用了一種特殊算法,保證生成主鍵的唯一性,支持SQL Server和MySQL

Hibernate包的作用

net.sf.hibernate.*
該包的類基本上都是接口類和異常類
net.sf.hibernate.cache.*
JCS的實現類
net.sf.hibernate.cfg.*
配置文件讀取類
net.sf.hibernate.collection.*
Hibernate集合接口實現類,例如List,Set,Bag等等,Hibernate之所以要自行編寫集合接口實現類是為了支持lazy loading
net.sf.hibernate.connection.*
幾個數據庫連接池的Provider
net.sf.hibernate.dialect.*
支持多種數據庫特性,每個Dialect實現類代表一種數據庫,描述了該數據庫支持數據類型和其它特點,例如是否有AutoIncrement,是否有Sequence,是否有分頁sql等等
net.sf.hibernate. eg.*
Hibernate文檔中用到的例子
net.sf.hibernate.engine.*
這個包的類作用比較散
net.sf.hibernate.expression.*
HQL支持的表達式
net.sf.hibernate.hq.*
HQL實現
net.sf.hibernate. id.*
ID生成器
net.sf.hibernate.impl.*
最核心的包,一些重要接口的實現類,如Session,SessionFactory,Query等
net.sf.hibernate.jca.*
JCA支持,把Session包裝為支持JCA的接口實現類
net.sf.hibernate.jmx.*
JMX是用來編寫App Server管理程序的,大概是JMX部分接口的實現,使得App Server可以通過JMX接口管理Hibernate
net.sf.hibernate.loader.*
也是很核心的包,主要是生成sql語句
net.sf.hibernate.lob.*
Blob和Clob支持
net.sf.hibernate.mapping.*
hbm文件的屬性實現
net.sf.hibernate.metadata.*
PO的Meta實現
net.sf.hibernate.odmg.*
ODMG是一個ORM標準,這個包是ODMG標準的實現類
net.sf.hibernate.persister.*
核心包,實現持久對象和表之間的映射
net.sf.hibernate.proxy.*
Proxy和Lazy Loading支持
net.sf.hibernate. ps.*
該包是PreparedStatment Cache
net.sf.hibernate.sql.*
生成JDBC sql語句的包
net.sf.hibernate.test.*
測試類,你可以用junit來測試Hibernate
net.sf.hibernate.tool.hbm2ddl.*
用hbm配置文件生成DDL
net.sf.hibernate.transaction.*
Hibernate Transaction實現類
net.sf.hibernate.type.*
Hibernate中定義的持久對象的屬性的數據類型
net.sf.hibernate.util.*
一些工具類,作用比較散
net.sf.hibernate.xml.*

Hibernate緩存管理

Hibernate 中提供了兩級Cache(高速緩衝存儲器),第一級別的緩存是Session級別的緩存,它是屬於事務範圍的緩存。這一級別的緩存由hibernate管理的,一般情況下無需進行干預;第二級別的緩存是SessionFactory級別的緩存,它是屬於進程範圍或集羣範圍的緩存。這一級別的緩存可以進行配置和更改,並且可以動態加載和卸載。 Hibernate還為查詢結果提供了一個查詢緩存,它依賴於第二級緩存。
事務範圍,每個事務都有單獨的第一級緩存進程範圍或集羣範圍,緩存被同一個進程或集羣範圍內的所有事務共享 併發訪問策略由於每個事務都擁有單獨的第一級緩存,不會出現併發問題,無需提供併發訪問策略由於多個事務會同時訪問第二級緩存中相同數據,因此必須提供適當的併發訪問策略,來保證特定的事務隔離級別數據過期策略沒有提供數據過期策略。處於一級緩存中的對象永遠不會過期,除非應用程序顯式清空緩存或者清除特定的對象必須提供數據過期策略,如基於內存的緩存中的對象的最大數目,允許對象處於緩存中的最長時間,以及允許對象處於緩存中的最長空閒時間
物理存儲介質內存和硬盤 對象的散裝數據首先存放在基於內存的緩存中,當內存中對象的數目達到數據過期策略中指定上限時,就會把其餘的對象寫入基於硬盤的緩存中。
緩存的軟件實現 在Hibernate的Session的實現中包含了緩存的實現由第三方提供,Hibernate僅提供了緩存適配器(CacheProvider)。用於把特定的緩存插件集成到Hibernate中。啓用緩存的方式只要應用程序通過Session接口來執行保存、更新、刪除、加載和查詢數據庫數據的操作,Hibernate就會啓用第一級緩存,把數據庫中的數據以對象的形式拷貝到緩存中,對於批量更新和批量刪除操作,如果不希望啓用第一級緩存,可以繞過Hibernate API,直接通過JDBC API來執行指操作。用户可以在單個類或類的單個集合的粒度上配置第二級緩存。如果類的實例被經常讀但很少被修改,就可以考慮使用第二級緩存。只有為某個類或集合配置了第二級緩存,Hibernate在運行時才會把它的實例加入到第二級緩存中。 用户管理緩存的方式第一級緩存的物理介質為內存,由於內存容量有限,必須通過恰當的檢索策略和檢索方式來限制加載對象的數目。Session的evict()方法可以顯式清空緩存中特定對象,但這種方法不值得推薦。 第二級緩存的物理介質可以是內存和硬盤,因此第二級緩存可以存放大量的數據,數據過期策略的maxElementsInMemory屬性值可以控制內存中的對象數目。管理第二級緩存主要包括兩個方面:選擇需要使用第二級緩存的持久類,設置合適的併發訪問策略:選擇緩存適配器,設置合適的數據過期策略。

Hibernate一級緩存

當應用程序調用Session的save()、update()、saveOrUpdate()、get()或load(),以及調用查詢接口的 list()、iterate()或filter()方法時,如果在Session緩存中還不存在相應的對象,Hibernate就會把該對象加入到第一級緩存中。當清理緩存時,Hibernate會根據緩存中對象的狀態變化來同步更新數據庫。 Session為應用程序提供了兩個管理緩存的方法: evict(Object obj):從緩存中清除參數指定的持久化對象。 clear():清空緩存中所有持久化對象。

Hibernate二級緩存

3.1. Hibernate的二級緩存策略的一般過程如下:
1) 條件查詢的時候,總是發出一條select * from table_name where …. (選擇所有字段)這樣的SQL語句查詢數據庫,一次獲得所有的數據對象
2) 把獲得的所有數據對象根據ID放入到第二級緩存中。
3) 當Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那麼從二級緩存中查;查不到,再查詢數據庫,把結果按照ID放入到緩存。
4) 刪除、更新、增加數據的時候,同時更新緩存。
Hibernate的二級緩存策略,是針對於ID查詢的緩存策略,對於條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的Query Cache。
3.2. 什麼樣的數據適合存放到第二級緩存中? 1 很少被修改的數據 2 不是很重要的數據,允許出現偶爾併發的數據 3 不會被併發訪問的數據 4 參考數據,指的是供應用參考的常量數據,它的實例數目有限,它的實例會被許多其他類的實例引用,實例極少或者從來不會被修改。
3.3. 不適合存放到第二級緩存的數據? 1 經常被修改的數據 2 財務數據,絕對不允許出現併發 3 與其他應用共享的數據。
3.4. 常用的緩存插件 Hibernater 的二級緩存是一個插件,下面是幾種常用的緩存插件:
l EhCache:可作為進程範圍的緩存,存放數據的物理介質可以是內存或硬盤,對Hibernate的查詢緩存提供了支持。
l OSCache:可作為進程範圍的緩存,存放數據的物理介質可以是內存或硬盤,提供了豐富的緩存數據過期策略,對Hibernate的查詢緩存提供了支持。
l SwarmCache:可作為羣集範圍內的緩存,但不支持Hibernate的查詢緩存。
l JBossCache:可作為羣集範圍內的緩存,支持事務型併發訪問策略,對Hibernate的查詢緩存提供了支持。
上述4種緩存插件的對比情況列於表9-3中。
表9-3 4種緩存插件的對比情況
緩 存 插 件
支 持 只 讀
支持非嚴格讀寫
支 持 讀 寫
支 持 事 務
EhCache

OSCache

SwarmCache


JBossCache


它們的提供器列於表9-4中。
表9-4 緩存策略的提供器
緩 存 插 件
提供器(Cache Providers)
Hashtable(只能測試時使用)
org.hibernate.cache.HashtableCacheProvider
EhCache
org.hibernate.cache.EhCacheProvider
OSCache
org.hibernate.cache.OSCacheProvider
在默認情況下,Hibernate使用EhCache進行JVM級別的緩存。用户可以通過設置Hibernate配置文件中的hibernate.cache.provider_class的屬性,指定其他的緩存策略,該緩存策略必須實現org.hibernate.cache.CacheProvider接口。配置二級緩存的主要步驟:
1) 選擇需要使用二級緩存的持久化類,設置它的命名緩存的併發訪問策略。這是最值得認真考慮的步驟。
2) 選擇合適的緩存插件,然後編輯該插件的配置文件。

Hibernate延遲加載

Hibernate對象關係映射提供延遲的與非延遲的對象初始化。非延遲加載在讀取一個對象的時候會將與這個對象所有相關的其他對象一起讀取出來。這有時會導致成百的(如果不是成千的話)select語句在讀取對象的時候執行。這個問題有時出現在使用雙向關係的時候,經常會導致整個數據庫都在初始化的階段被讀出來了。當然,你可以不厭其煩地檢查每一個對象與其他對象的關係,並把那些最昂貴的刪除,但是到最後,我們可能會因此失去了本想在ORM工具中獲得的便利。
一個明顯的解決方法是使用Hibernate提供的延遲加載機制。這種初始化策略只在一個對象調用它的一對多或多對多關係時才將關係對象讀取出來。這個過程對開發者來説是透明的,而且只進行了很少的數據庫操作請求,因此會得到比較明顯的性能提升。這項技術的一個缺陷是延遲加載技術要求一個Hibernate會話要在對象使用的時候一直開着。這會成為通過使用DAO模式將持久層抽象出來時的一個主要問題。為了將持久化機制完全地抽象出來,所有的數據庫邏輯,包括打開或關閉會話,都不能在應用層出現。最常見的是,一些實現了簡單接口的DAO實現類將數據庫邏輯完全封裝起來了。一種快速但是笨拙的解決方法是放棄DAO模式,將數據庫連接邏輯加到應用層中來。這可能對一些小的應用程序有效,但是在大的系統中,這是一個嚴重的設計缺陷,妨礙了系統的可擴展性
Hibernate有關書籍
Hibernate有關書籍(10張)
幸運的是,Spring框架為Hibernate延遲加載與DAO模式的整合提供了一種方便的解決方法。以一個Web應用為例,Spring提供了OpenSessionInViewFilter和OpenSessionInViewInterceptor。我們可以隨意選擇一個類來實現相同的功能。兩種方法唯一的不同就在於interceptor在Spring容器中運行並被配置在web應用的上下文中,而Filter在Spring之前運行並被配置在web.xml中。不管用哪個,他們都在請求將當前會話與當前(數據庫)線程綁定時打開Hibernate會話。一旦已綁定到線程,這個打開了的Hibernate會話可以在DAO實現類中透明地使用。這個會話會為延遲加載數據庫中值對象的視圖保持打開狀態。一旦這個邏輯視圖完成了,Hibernate會話會在Filter的doFilter方法或者Interceptor的postHandle方法中被關閉。
實現方法在web.xml中加入
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>

Hibernate性能優化

初用HIBERNATE的人也許都遇到過性能問題,實現同一功能,用HIBERNATE與用JDBC性能相差十幾倍很正常,如果不及早調整,很可能影響整個項目的進度。 大體上,對於HIBERNATE性能調優的主要考慮點如下:
.HQL優化
.API的正確使用(如根據不同的業務類型選用不同的集合及查詢API)
.主配置參數(日誌,查詢緩存,fetch_size, batch_size等)
.映射文件優化(ID生成策略,二級緩存,延遲加載,關聯優化)
.一級緩存的管理
.針對二級緩存,還有許多特有的策略
.事務控制策略

Hibernate數據庫設計

a) 降低關聯的複雜性
b) 儘量不使用聯合主鍵
c) ID的生成機制,不同的數據庫所提供的機制並不完全一樣
d) 適當的冗餘數據,不過分追求高範式

HibernateHQL優化

HQL如果拋開它同HIBERNATE本身一些緩存機制的關聯,HQL的優化技巧同普通的SQL優化技巧一樣,可以很容易在網上找到一些經驗之談。

Hibernate主配置

a) 查詢緩存,同下面講的緩存不太一樣,它是針對HQL語句的緩存,即完全一樣的語句再次執行時可以利用緩存數據。但是,查詢緩存在一個交易系統(數據變更頻繁,查詢條件相同的機率並不大)中可能會起反作用:它會白白耗費大量的系統資源但卻難以派上用場。
b) fetch_size,同JDBC的相關參數作用類似,參數並不是越大越好,而應根據業務特徵去設置
c) batch_size同上。
d) 生產系統中,切記要關掉SQL語句打印。

Hibernate緩存

a) 數據庫級緩存:這級緩存是最高效和安全的,但不同的數據庫可管理的層次並不一樣,比如,在Oracle中,可以在建表時指定將整個表置於緩存當中。
b) SESSION緩存:在一個HibernateSESSION有效,這級緩存的可干預性不強,大多於HIBERNATE自動管理,但它提供清除緩存的方法,這在大批量增加/更新操作是有效的。比如,同時增加十萬條記錄,按常規方式進行,很可能會發現OutofMemeroy的異常,這時可能需要手動清除這一級緩存:Session.evict以及 Session.clear
c) 應用緩存:在一個SESSIONFACTORY中有效,因此也是優化的重中之重,因此,各類策略也考慮的較多,在將數據放入這一級緩存之前,需要考慮一些前提條件:
i. 數據不會被第三方修改(比如,是否有另一個應用也在修改這些數據?)
ii. 數據不會太大
iii. 數據不會頻繁更新(否則使用CACHE可能適得其反)
iv. 數據會被頻繁查詢
v. 數據不是關鍵數據(如涉及錢,安全等方面的問題)。
緩存有幾種形式,可以在映射文件中配置:read-only(只讀,適用於很少變更的靜態數據/歷史數據),nonstrict-read- write,read-write(比較普遍的形式,效率一般),transactional(JTA中,且支持的緩存產品較少)
d) 分佈式緩存:同c)的配置一樣,只是緩存產品的選用不同,oscache, jboss cache,的大多數項目,對它們的用於集羣的使用(特別是關鍵交易系統)都持保守態度。在集羣環境中,只利用數據庫級的緩存是最安全的。

Hibernate延遲加載

a) 實體延遲加載:通過使用動態代理實現
b) 集合延遲加載:通過實現自有的SET/LIST,HIBERNATE提供了這方面的支持
c) 屬性延遲加載:

Hibernate方法選用

a) 完成同樣一件事,Hibernate提供了可供選擇的一些方式,使用不同的編碼方式對性能有不同的影響。比如:一次返回十萬條記錄,如果用 (List/Set/Bag/Map等)進行處理,很可能導致內存不夠的問題,而如果用基於遊標(ScrollableResults)或 Iterator的結果集,則不存在這樣的問題。
b) Session的load/get方法,前者會使用二級緩存,而後者則不使用。
c) Query和list/iterator,如果去仔細研究一下它們,你可能會發現很多有意思的情況,二者主要區別(如果使用了Spring,在HibernateTemplate中對應find,iterator方法):
i. list只能利用查詢緩存(但在交易系統中查詢緩存作用不大),無法利用二級緩存中的單個實體,但list查出的對象會寫入二級緩存,但它一般只生成較少的執行SQL語句,很多情況就是一條(無關聯)。
ii. iterator則可以利用二級緩存,對於一條查詢語句,它會先從數據庫中找出所有符合條件的記錄的ID,再通過ID去緩存找,對於緩存中沒有的記錄,再構造語句從數據庫中查出,因此很容易知道,如果緩存中沒有任何符合條件的記錄,使用iterator會產生N+1條SQL語句(N為符合條件的記錄數)
iii. 通過iterator,配合緩存管理API,在海量數據查詢中可以很好的解決內存問題,如:
while(it.hasNext()){
YouObject object = (YouObject)it.next();
session.evict(youObject);
sessionFactory.evice(YouObject.class, youObject.getId());
}
如果用list方法,很可能就出OutofMemory錯誤了。

Hibernate集合的選用

在Hibernate3.1文檔的“19.5. Understanding Collection performance”中有詳細的説明。

Hibernate事務控制

事務方面對性能有影響的主要包括:事務方式的選用,事務隔離級別以及鎖的選用
a) 事務方式選用:如果不涉及多個事務管理器事務的話,不需要使用JTA,只有
JDBC的事務控制就可以。
b) 事務隔離級別:參見標準的SQL事務隔離級別
c) 鎖的選用:悲觀鎖(一般由具體的事務管理器實現),對於長事務效率低,但安全。樂觀鎖(一般在應用級別實現),如在HIBERNATE中可以定義 VERSION字段,顯然,如果有多個應用操作數據,且這些應用不是用同一種樂觀鎖機制,則樂觀鎖會失效。因此,針對不同的數據應有不同的策略,同前面許多情況一樣,很多時候我們是在效率與安全/準確性上找一個平衡點,無論如何,優化都不是一個純技術的問題,你應該對你的應用和業務特徵有足夠的瞭解。

Hibernate批量操作

即使是使用JDBC,在進行大批數據更新時,BATCH與不使用BATCH有效率上也有很大的差別。可以通過設置batch_size來讓其支持批量操作。
舉個例子,要批量刪除某表中的對象,如“delete Account”,打出來的語句,HIBERNATE找出了所有ACCOUNT的ID,再進行刪除,這主要是為了維護二級緩存,這樣效率肯定高不了,在後續的版本中增加了bulk delete/update,但這也無法解決緩存的維護問題。也就是説,由於有了二級緩存的維護問題,HIBERNATE的批量操作效率並不盡如人意。
hibernate工作原理:
1、通過Configuration().configure();讀取並解析hibernate.cfg.xml配置文件
2、由hibernate.cfg.xml中的<mappingresource="com/xx/User.hbm.xml"/>讀取解析映射信息。
3、通過config.buildSessionFactory();//得到sessionFactory。
4、sessionFactory.openSession();//得到session。
5、session.beginTransaction();//開啓事務。
6、persistent operate;
7、session.getTransaction().commit();//提交事務
8、關閉session;
9、關閉sessionFactory;
hibernate優點:
1、封裝了jdbc,簡化了很多重複性代碼。
2、簡化了DAO層編碼工作,使開發更對象化了。
3、移植性好,支持各種數據庫,如果換個數據庫只要在配置文件中變換配置就可以了,不用改變hibernate代碼。
4、支持透明持久化,因為hibernate操作的是純粹的(pojo)java類,沒有實現任何接口,沒有侵入性。所以説它是一個輕量級框架
hibernate延遲加載
get不支持延遲加載,load支持延遲加載。
1、hibernate2對 實體對象和集合 實現了延遲加載
2、hibernate3對 提供了屬性的延遲加載功能
hibernate延遲加載就是當使用session.load(User.class,1)或者session.createQuery()查詢對象或者屬性的時候
這個對象或者屬性並沒有在內存中,只有當程序操作數據的時候,才會存在內存中,這樣就實現延遲加載,節省了內存的開銷,從而提高了服務器的性能。
Hibernate的緩存機制
一級緩存:session級的緩存也叫事務級的緩存,只緩存實體,生命週期和session一致。不能對其進行管理。
不用顯式的調用。
二級緩存:sessionFactory緩存,也叫進程級的緩存,使用第3方插件實現的,也只緩存實體,生命週期和sessionFactory一致,可以進行管理。
首先配置第3方插件,我們用的是EHCache,在hibernate.cfg.xml文件中加入
<propertyname="hibernate.cache.user_second_level_cache">true</property>
在映射中也要顯式的調用,<cacheusage="read-only"/>
二級緩存之查詢緩存:對普通屬性進行緩存。如果關聯的表發生了修改,那麼查詢緩存的生命週期也結束了。
在程序中必須手動啓用查詢緩存:query.setCacheable(true);
優化Hibernate
1、使用一對多雙向關聯,儘量從多的一端維護。
2、不要使用一對一,儘量使用多對一
3、配置對象緩存,不要使用集合緩存。
4、表字段要少,表關聯不要怕多,有二級緩存撐腰。
hibernate 類與類之間關係
聚集關係
繼承關係
Hibernate繼承關係映射策略分為三種:一張表對應一整棵類繼承樹、一個類對應一張表、每一個具體類對應一張表。
參考資料