簡介
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 模式實現業務邏輯與表示層的分開。表示層和用戶實現交互,業務邏輯層處理數據持久化操作。将第二階段業務邏輯層的功能部署拆分後,業務邏輯層完成核心業務邏輯處理,持久層完成對象持久化。降低業務邏輯層複雜度的同時将數據持久化讓其他組件完成。
發展曆程
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标準。
編程開發
編程環境
Hibernate是一個以LGPL(Lesser GNU Public License)許可證形式發布的開源項目。在Hibernate官網上有下載Hibernate包的說明。Hibernate包以源代碼或者二進制的形式提供。
編程工具
Eclipse:一個開放源代碼的、基于Java的可擴展開發平台。
NetBeans:開放源碼的Java集成開發環境,适用于各種客戶機和Web應用。
IntelliJ IDEA:在代碼自動提示、代碼分析等方面的具有很好的功能。
MyEclipse:由Genuitec公司開發的一款商業化軟件,是應用比較廣泛的Java應用程序集成開發環境。
EditPlus:如果正确配置Java的編譯器“Javac”以及解釋器“Java”後,可直接使用EditPlus編譯執行Java程序。
語言特點
将對數據庫的操作轉換為對Java對象的操作,從而簡化開發。通過修改一個“持久化”對象的屬性從而修改數據庫表中對應的記錄數據。
提供線程和進程兩個級别的緩存提升應用程序性能。
有豐富的映射方式将Java對象之間的關系轉換為數據庫表之間的關系。
屏蔽不同數據庫實現之間的差異。在Hibernate中隻需要通過“方言”的形式指定當前使用的數據庫,就可以根據底層數據庫的實際情況生成适合的SQL語句。
非侵入式:Hibernate不要求持久化類實現任何接口或繼承任何類,POJO即可。
核心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版本更新速度很快,有多個階段性的版本: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的版本
主鍵介紹
Assigned
Assigned方式由用戶生成主鍵值,并且要在save()之前指定否則會抛出異常
特點:主鍵的生成值完全由用戶決定,與底層數據庫無關。用戶需要維護主鍵值,在調用session.save()之前要指定主鍵值。
Hilo
Hibernate相關書籍
Hilo使用高低位算法生成主鍵,高低位算法使用一個高位值和一個低位值,然後把算法得到的兩個值拼接起來作為數據庫中的唯一主鍵。Hilo方式需要額外的數據庫表和字段提供高位值來源。默認情況下使用的表是
hibernate_unique_key,默認字段叫作next_hi。next_hi必須有一條記錄否則會出現錯誤。
特點:需要額外的數據庫表的支持,能保證同一個數據庫中主鍵的唯一性,但不能保證多個數據庫之間主鍵的唯一性。Hilo主鍵生成方式由Hibernate 維護,所以Hilo方式與底層數據庫無關,但不應該手動修改hi/lo算法使用的表的值,否則會引起主鍵重複的異常。
Increment
Increment方式對主鍵值采取自動增長的方式生成新的主鍵值,但要求底層數據庫的主鍵類型為long,int等數值型。主鍵按數值順序遞增,增量為1。
/*特點:由Hibernate本身維護,适用于所有的數據庫,不适合多進程并發更新數據庫,适合單一進程訪問數據庫。不能用于群集環境。*/
Identity
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
UUID使用128位UUID算法生成主鍵,能夠保證網絡環境下的主鍵唯一性,也就能夠保證在不同數據庫及不同服務器下主鍵的唯一性。特點:能夠保證數據庫中的主鍵唯一性,生成的主鍵占用比較多的存貯空間
Foreign GUID
Foreign用于一對一關系中。GUID主鍵生成方式使用了一種特殊算法,保證生成主鍵的唯一性,支持SQL Server和MySQL
包的作用
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.*
XML數據綁定
緩存管理
Hibernate 中提供了兩級Cache(高速緩沖存儲器),第一級别的緩存是Session級别的緩存,它是屬于事務範圍的緩存。這一級别的緩存由hibernate管理的,一般情況下無需進行幹預;第二級别的緩存是SessionFactory級别的緩存,它是屬于進程範圍或集群範圍的緩存。這一級别的緩存可以進行配置和更改,并且可以動态加載和卸載。 Hibernate還為查詢結果提供了一個查詢緩存,它依賴于第二級緩存。
事務範圍,每個事務都有單獨的第一級緩存進程範圍或集群範圍,緩存被同一個進程或集群範圍内的所有事務共享 并發訪問策略由于每個事務都擁有單獨的第一級緩存,不會出現并發問題,無需提供并發訪問策略由于多個事務會同時訪問第二級緩存中相同數據,因此必須提供适當的并發訪問策略,來保證特定的事務隔離級别數據過期策略沒有提供數據過期策略。處于一級緩存中的對象永遠不會過期,除非應用程序顯式清空緩存或者清除特定的對象必須提供數據過期策略,如基于内存的緩存中的對象的最大數目,允許對象處于緩存中的最長時間,以及允許對象處于緩存中的最長空閑時間。
物理存儲介質内存和硬盤 對象的散裝數據首先存放在基于内存的緩存中,當内存中對象的數目達到數據過期策略中指定上限時,就會把其餘的對象寫入基于硬盤的緩存中。
緩存的軟件實現 在Hibernate的Session的實現中包含了緩存的實現由第三方提供,Hibernate僅提供了緩存适配器(CacheProvider)。用于把特定的緩存插件集成到Hibernate中。啟用緩存的方式隻要應用程序通過Session接口來執行保存、更新、删除、加載和查詢數據庫數據的操作,Hibernate就會啟用第一級緩存,把數據庫中的數據以對象的形式拷貝到緩存中,對于批量更新和批量删除操作,如果不希望啟用第一級緩存,可以繞過Hibernate API,直接通過JDBC API來執行指操作。用戶可以在單個類或類的單個集合的粒度上配置第二級緩存。如果類的實例被經常讀但很少被修改,就可以考慮使用第二級緩存。隻有為某個類或集合配置了第二級緩存,Hibernate在運行時才會把它的實例加入到第二級緩存中。 用戶管理緩存的方式第一級緩存的物理介質為内存,由于内存容量有限,必須通過恰當的檢索策略和檢索方式來限制加載對象的數目。Session的evict()方法可以顯式清空緩存中特定對象,但這種方法不值得推薦。 第二級緩存的物理介質可以是内存和硬盤,因此第二級緩存可以存放大量的數據,數據過期策略的maxElementsInMemory屬性值可以控制内存中的對象數目。管理第二級緩存主要包括兩個方面:選擇需要使用第二級緩存的持久類,設置合适的并發訪問策略:選擇緩存适配器,設置合适的數據過期策略。
一級緩存
當應用程序調用Session的save()、update()、saveOrUpdate()、get()或load(),以及調用查詢接口的 list()、iterate()或filter()方法時,如果在Session緩存中還不存在相應的對象,Hibernate就會把該對象加入到第一級緩存中。當清理緩存時,Hibernate會根據緩存中對象的狀态變化來同步更新數據庫。 Session為應用程序提供了兩個管理緩存的方法: evict(Object obj):從緩存中清除參數指定的持久化對象。 clear():清空緩存中所有持久化對象。
二級緩存
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種緩存插件的對比情況
它們的提供器列于表9-4中。
表9-4 緩存策略的提供器
在默認情況下,Hibernate使用EhCache進行JVM級别的緩存。用戶可以通過設置Hibernate配置文件中的hibernate.cache.provider_class的屬性,指定其他的緩存策略,該緩存策略必須實現org.hibernate.cache.CacheProvider接口。配置二級緩存的主要步驟:
1) 選擇需要使用二級緩存的持久化類,設置它的命名緩存的并發訪問策略。這是最值得認真考慮的步驟。
2) 選擇合适的緩存插件,然後編輯該插件的配置文件。
延遲加載
Hibernate對象關系映射提供延遲的與非延遲的對象初始化。非延遲加載在讀取一個對象的時候會将與這個對象所有相關的其他對象一起讀取出來。這有時會導緻成百的(如果不是成千的話)select語句在讀取對象的時候執行。這個問題有時出現在使用雙向關系的時候,經常會導緻整個數據庫都在初始化的階段被讀出來了。當然,你可以不厭其煩地檢查每一個對象與其他對象的關系,并把那些最昂貴的删除,但是到最後,我們可能會因此失去了本想在ORM工具中獲得的便利。
一個明顯的解決方法是使用Hibernate提供的延遲加載機制。這種初始化策略隻在一個對象調用它的一對多或多對多關系時才将關系對象讀取出來。這個過程對開發者來說是透明的,而且隻進行了很少的數據庫操作請求,因此會得到比較明顯的性能提升。這項技術的一個缺陷是延遲加載技術要求一個Hibernate會話要在對象使用的時候一直開着。這會成為通過使用DAO模式将持久層抽象出來時的一個主要問題。為了将持久化機制完全地抽象出來,所有的數據庫邏輯,包括打開或關閉會話,都不能在應用層出現。最常見的是,一些實現了簡單接口的DAO實現類将數據庫邏輯完全封裝起來了。一種快速但是笨拙的解決方法是放棄DAO模式,将數據庫連接邏輯加到應用層中來。這可能對一些小的應用程序有效,但是在大的系統中,這是一個嚴重的設計缺陷,妨礙了系統的可擴展性。
幸運的是,Spring框架為Hibernate延遲加載與DAO模式的整合提供了一種方便的解決方法。以一個Web應用為例,Spring提供了OpenSessionInViewFilter和OpenSessionInViewInterceptor。我們可以随意選擇一個類來實現相同的功能。兩種方法唯一的不同就在于interceptor在Spring容器中運行并被配置在web應用的上下文中,而Filter在Spring之前運行并被配置在web.xml中。不管用哪個,他們都在請求将當前會話與當前(數據庫)線程綁定時打開Hibernate會話。一旦已綁定到線程,這個打開了的Hibernate會話可以在DAO實現類中透明地使用。這個會話會為延遲加載數據庫中值對象的視圖保持打開狀态。一旦這個邏輯視圖完成了,Hibernate會話會在Filter的doFilter方法或者Interceptor的postHandle方法中被關閉。
實現方法在web.xml中加入
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
性能優化
初用HIBERNATE的人也許都遇到過性能問題,實現同一功能,用HIBERNATE與用JDBC性能相差十幾倍很正常,如果不及早調整,很可能影響整個項目的進度。 大體上,對于HIBERNATE性能調優的主要考慮點如下:
.數據庫設計調整
.HQL優化
.API的正确使用(如根據不同的業務類型選用不同的集合及查詢API)
.主配置參數(日志,查詢緩存,fetch_size, batch_size等)
.映射文件優化(ID生成策略,二級緩存,延遲加載,關聯優化)
.一級緩存的管理
.針對二級緩存,還有許多特有的策略
.事務控制策略。
數據庫設計
a) 降低關聯的複雜性
b) 盡量不使用聯合主鍵
c) ID的生成機制,不同的數據庫所提供的機制并不完全一樣
d) 适當的冗餘數據,不過分追求高範式
HQL優化
HQL如果抛開它同HIBERNATE本身一些緩存機制的關聯,HQL的優化技巧同普通的SQL優化技巧一樣,可以很容易在網上找到一些經驗之談。
主配置
a) 查詢緩存,同下面講的緩存不太一樣,它是針對HQL語句的緩存,即完全一樣的語句再次執行時可以利用緩存數據。但是,查詢緩存在一個交易系統(數據變更頻繁,查詢條件相同的機率并不大)中可能會起反作用:它會白白耗費大量的系統資源但卻難以派上用場。
b) fetch_size,同JDBC的相關參數作用類似,參數并不是越大越好,而應根據業務特征去設置
c) batch_size同上。
d) 生産系統中,切記要關掉SQL語句打印。
緩存
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,的大多數項目,對它們的用于集群的使用(特别是關鍵交易系統)都持保守态度。在集群環境中,隻利用數據庫級的緩存是最安全的。
延遲加載
a) 實體延遲加載:通過使用動态代理實現
b) 集合延遲加載:通過實現自有的SET/LIST,HIBERNATE提供了這方面的支持
c) 屬性延遲加載:
方法選用
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錯誤了。
集合的選用
在Hibernate3.1文檔的“19.5. Understanding Collection performance”中有詳細的說明。
事務控制
事務方面對性能有影響的主要包括:事務方式的選用,事務隔離級别以及鎖的選用
a) 事務方式選用:如果不涉及多個事務管理器事務的話,不需要使用JTA,隻有
JDBC的事務控制就可以。
b) 事務隔離級别:參見标準的SQL事務隔離級别
c) 鎖的選用:悲觀鎖(一般由具體的事務管理器實現),對于長事務效率低,但安全。樂觀鎖(一般在應用級别實現),如在HIBERNATE中可以定義 VERSION字段,顯然,如果有多個應用操作數據,且這些應用不是用同一種樂觀鎖機制,則樂觀鎖會失效。因此,針對不同的數據應有不同的策略,同前面許多情況一樣,很多時候我們是在效率與安全/準确性上找一個平衡點,無論如何,優化都不是一個純技術的問題,你應該對你的應用和業務特征有足夠的了解。
批量操作
即使是使用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中的
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文件中加入
在映射中也要顯式的調用,
二級緩存之查詢緩存:對普通屬性進行緩存。如果關聯的表發生了修改,那麼查詢緩存的生命周期也結束了。
在程序中必須手動啟用查詢緩存:query.setCacheable(true);
優化Hibernate
1、使用一對多的雙向關聯,盡量從多的一端維護。
2、不要使用一對一,盡量使用多對一。
3、配置對象緩存,不要使用集合緩存。
4、表字段要少,表關聯不要怕多,有二級緩存撐腰。
hibernate 類與類之間關系
關聯關系
聚集關系
繼承關系
Hibernate繼承關系映射策略分為三種:一張表對應一整棵類繼承樹、一個類對應一張表、每一個具體類對應一張表。


















