一.
????????????
序
在實(shí)際項(xiàng)目中使用Hibernate有兩年多了,在兩年多的實(shí)踐過程中既體驗(yàn)到了Hibernate帶來的N多好處,同時(shí)也碰到不少的問題,特寫此篇文章做個(gè)總結(jié),記錄自己在Hibernate實(shí)踐中的一些經(jīng)驗(yàn),希望對于新使用Hibernate的朋友能有個(gè)幫助,避免走過多的彎路。
閱讀本文前建議至少擁有Hibernate的一些基本知識(shí),因?yàn)楸疚牟粫?huì)去詳細(xì)介紹相關(guān)的基本知識(shí),最好就是先用Hibernate開發(fā)了一個(gè)HelloWorld,^_^。
根據(jù)自己所經(jīng)歷的項(xiàng)目中使用Hibernate所涉及的范圍,本文從開發(fā)環(huán)境、開發(fā)、設(shè)計(jì)、性能、測試以及推薦的相關(guān)書籍方面進(jìn)行講述,本篇文檔不會(huì)講的非常細(xì)致,只是根據(jù)自己在實(shí)踐時(shí)的經(jīng)驗(yàn)提出一些建議,關(guān)于細(xì)致以及具體的部分請參閱《Hibernate Reference》或推薦的相關(guān)書籍章節(jié)。
此文檔的PDF版本請到此下載:
http://www.tkk7.com/Files/BlueDavy/Hibernate
實(shí)踐.rar
本文允許轉(zhuǎn)載,但轉(zhuǎn)載時(shí)請注明作者以及來源。
作者:BlueDavy
來源:www.tkk7.com/BlueDavy
二.
????????????
開發(fā)環(huán)境
Hibernate
開發(fā)環(huán)境的搭建非常的簡單,不過為了提高基于Hibernate開發(fā)的效率,通常都需要使用一些輔助工具,如xdoclet、middlegen等。
盡管Hibernate已經(jīng)封裝提供了很簡單的進(jìn)行持久的方法,但在實(shí)際項(xiàng)目的使用中基本還是要提供一些通用的代碼,以便在進(jìn)行持久的相關(guān)操作的時(shí)候能夠更加的方便。
2.1.
lib
2.1.1.
??????
Hibernate lib
Hibernate
相關(guān)的
lib
自然是開發(fā)環(huán)境中首要的問題,這部分可以從
Hibernate
的官方網(wǎng)站進(jìn)行下載,在其官方網(wǎng)站中同時(shí)提供了對于
Hibernate
所必須依賴的
lib
以及其他可選
lib
的介紹。
2.2.
xdoclet
Hibernate
作為ORM工具,從名字上就能看出它需要一個(gè)從O
à
R
的Mapping的描述,而這個(gè)描述就是在使用Hibernate時(shí)常見的hbm.xml,在沒有工具支持的情況下,需要在編寫持久層對象的同時(shí)手寫這個(gè)文件,甚為不便。
在jdk 5.0未推出之前,xdoclet支持的在javadoc中編寫注釋生成相關(guān)配置文件的方式大受歡迎,減少了編寫hibernate映射文件的復(fù)雜性,手寫一個(gè)完整的hibernate映射文件出錯(cuò)幾率比較的高,再加上手寫容易造成編寫出來的風(fēng)格相差很大,因此,基于xdoclet來生成hbm.xml的方式被大量的采用,基于xdoclet來編寫能夠基于我們在持久層對象上編寫的javadoc來生成hbm.xml文件,非常的方便。
2.2.1.
??????
Hibernate template
如果沒記錯(cuò)的話,大概在
04
年的時(shí)候
javaeye
上有位同仁整理了一個(gè)這樣的
template
文件,
^_^
,非常感謝,我一直都在用著,呵呵。
這個(gè)文件的方便就是把它導(dǎo)入
eclipse
后,在
javadoc
中我們可以直接寫
hibid
,然后按
eclipse
的代碼輔助鍵
(alt+/)
來生成整個(gè)
hibernate.id
的相關(guān)的格式,呵呵,免得在寫
hibernate.id
這些東西的時(shí)候過于麻煩,
^_^
,這個(gè)
template
文件我稍微做了修改,可在這里下載:
http://www.tkk7.com/Files/BlueDavy/templates-eclipse-tags.rar
當(dāng)然,你也可以選擇直接用
xdoclet
提供的
template
文件,不過
xdoclet
官方網(wǎng)站上好像只提供了可直接導(dǎo)入
idea
的模板文件。
關(guān)于注釋上的
hibernate.id
這些東西具體請參見
xdoclet
官方網(wǎng)站的說明。
如果你的項(xiàng)目采用的是
jdk 5
,那么就可以直接使用
hibernate annotation
了,那就更為方便。
2.2.2.
??????
Ant task build
Eclipse
里沒有集成
xdoclet
的插件,你也可以去安裝一個(gè)
jboss ide
的插件,里面有
xdoclet
的插件,反正我是覺得太麻煩了。
在項(xiàng)目中我仍然采用
ant task
的方式來生成
hbm.xml
,
target
如下所示:
<path id="app.classpath">
<pathelement path="${java.class.path}"/>
<fileset dir="${xdoclib.dir}">
<include name="*.jar"/>
</fileset>
</path>
<target name="hbm" description="
生成映射文件
">
<tstamp>
<format property="TODAY" pattern="yy-MM-dd"/>
</tstamp>
<taskdef name="hibernatedoclet" classname="xdoclet.modules.hibernate.HibernateDocletTask" classpathref="app.classpath"/>
<hibernatedoclet destdir="src/java" force="true" verbose="true" excludedtags="@version,@author,@todo">
<fileset dir="src/java"> ?
<include name="**/po/**/*.java"/>
</fileset>
<hibernate version ="3.0"/>
</hibernatedoclet>
</target>
這個(gè)文件請根據(jù)項(xiàng)目情況以及環(huán)境稍做修改,
^_^
,其中需要通過
properties
文件指明
xdocletlib.dir
,類似
xdocletlib.dir=c:\xdocletlib
,里面放置
xdoclet
的相關(guān)
jar
文件。
在搭建好了這樣的環(huán)境后,就可以在直接在
eclipse
中運(yùn)行
ant
文件中的這個(gè)
target
來生成
hbm.xml
。
2.3.
Hibernate3 Tools
如果采用Hibernate 3,則可以直接下載Hibernate 3 Tools的Eclipse Plugin,那就可以類似在PL/SQL里執(zhí)行sql一樣在eclipse里執(zhí)行hql,^_^
2.4.
HibernateUtil
為了方便項(xiàng)目中Hibernate的使用,一般來說都會(huì)提供HibernateUtil這樣的類,這個(gè)類的作用主要是創(chuàng)建sessionFactory和管理session,在Hibernate 3以前采用的是在這里建立ThreadLocal來存放session,在Hibernate 3以后則可以直接使用SessionFactory.getCurrentSession來獲取session,而session的獲取方式則可通過在hibernate.cfg.xml中執(zhí)行current_session_context_class的屬性來決定是采用thread或jta或自定義的方式來產(chǎn)生session。
2.5.
CommonDao
在持久層部分目前采用的較多的仍然是dao模式,Hibernate作為ORM工具已經(jīng)提供了CRUD的封裝,類如可以使用session.save();session.persist()這樣簡單的方式來完成CRUD的操作,但在實(shí)際的項(xiàng)目中還是需要提供一個(gè)通用的Dao,來簡化對于事務(wù)、異常處理以及session的操作,同時(shí)提供一些項(xiàng)目中需要的相關(guān)操作。
三.
????????????
開發(fā)
在完成了Hibernate的開發(fā)環(huán)境的搭建后,就可以基于Hibernate進(jìn)行持久層的開發(fā)了,對于持久層開發(fā)來說,會(huì)涉及到實(shí)體的編寫、實(shí)體的維護(hù)以及實(shí)體的查詢?nèi)齻€(gè)部分。
3.1.
實(shí)體的編寫
Hibernate
的一個(gè)明顯的優(yōu)點(diǎn)就是在于可透明化的對對象進(jìn)行持久,這也就意味著持久對象根本就不需要依賴任何的東西,可以采用POJO的方式來編寫,在Hibernate 3以上版本還提供了對于Map、XML的方式的持久的支持,就更方便了,在項(xiàng)目中,更多采用的仍然是POJO的方式。
在實(shí)體的編寫上應(yīng)該說不會(huì)有什么問題,只要仔細(xì)查看xdoclet關(guān)于hibernatedoclet部分的說明即可完成。
這塊需要學(xué)習(xí)的主要是普通的值類型注釋的編寫、id字段注釋的編寫、關(guān)聯(lián)注釋的編寫,這些部分xdoclet均提供了較詳細(xì)的說明。
3.2.
實(shí)體的維護(hù)
3.2.1.
??????
新增
/
編輯
/
刪除
新增
/
編輯
/
刪除是持久操作中最常使用的維護(hù)性操作,基于
Hibernate
做這樣的維護(hù)就比采用
sql
的方式簡單多了,通過上面
CommonDao
,就可以直接完成
dao.save
、
dao.update
、
dao.delete
的操作,而且在
Hibernate 3
也支持了批量的
insert
、
update
和
delete
。
這個(gè)部分中需要注意的是
Hibernate
對于對象的三種狀態(tài)的定義:
u??????
Transient
很容易理解,就是從未與
session
發(fā)生過關(guān)系的對象,
^_^
,例如在代碼中直接
User user=new User()
;這樣形成的
user
對象,就稱為
Transient
對象了。
u??????
Detached
同樣很容易理解,就是與
session
發(fā)生過關(guān)系的對象,但
session
已經(jīng)關(guān)閉了的情況下存在的對象,例如:
User user=new User();
user.setName(“bluedavy”);
session.save(user);
session.close();
在
session.close()
后這個(gè)時(shí)候的
user
對象就處于
Detached
狀態(tài)之中了,如果想將這個(gè)對象變?yōu)?/span>
Persistent
狀態(tài),可以通過
session.merge
或
session.saveOrUpdate()
等方式來實(shí)現(xiàn)。
Detached
狀態(tài)的對象在實(shí)際的應(yīng)用中最常采用,從概念上我們可以這么理解,處于
Detached
狀態(tài)的對象可以看做是一個(gè)
DTO
,而不是
PO
,這從很大程度上就方便了
PO
在實(shí)際項(xiàng)目中的使用了。
u??????
Persistent
Persistent
狀態(tài)就是指和
Session
發(fā)生了關(guān)系的對象,并且此時(shí)
session
未關(guān)閉,舉例如下:
User user=new User();
user.setName(“bluedavy”);
session.save(user);
user.getName();
在
session.save
后
user
就處于
Persistent
狀態(tài),此時(shí)如果通過
session
根據(jù)
user
的
id
去獲取
user
對象,則可發(fā)現(xiàn)獲取的對象和之前的
user
是同一個(gè)對象,這是
session
一級緩存所起的作用了,當(dāng)然,也可以強(qiáng)制的刷新
session
的一級緩存,讓
session
從數(shù)據(jù)庫中重新獲取,只需要在獲取前執(zhí)行
session.evict(user)
或
session.clear()
。
3.2.2.
??????
關(guān)聯(lián)維護(hù)
關(guān)聯(lián)維護(hù)在
Hibernate
中表現(xiàn)出來可能會(huì)讓熟悉使用
sql
的人有些的不熟,但其實(shí)以對象的觀點(diǎn)去看是會(huì)覺得很正常的。
在
Hibernate
的關(guān)聯(lián)維護(hù)中,最重要的是
inverse
和
cascade
兩個(gè)概念。
u??????
inverse
inverse
從詞義上看過去可能不是那么容易理解,其實(shí)它的意思就是由誰來控制關(guān)聯(lián)關(guān)系的自動(dòng)維護(hù),當(dāng)
inverse=true
就意味著當(dāng)前對象是不能自動(dòng)維護(hù)關(guān)聯(lián)關(guān)系,當(dāng)
inverse=false
就意味著當(dāng)前對象可自動(dòng)維護(hù)關(guān)聯(lián)關(guān)系,還是舉例來說:
假設(shè)
Org
和
User
一對多關(guān)聯(lián),
當(dāng)
org
中
getUsers
的
inverse=false
的情況:
org.getUsers().add(user);
dao.save(org);
這樣執(zhí)行后將會(huì)看到數(shù)據(jù)庫中
user
這條記錄中的
orgId
已經(jīng)被設(shè)置上去了。
當(dāng)
inverse=true
的情況下,執(zhí)行上面的代碼,會(huì)發(fā)現(xiàn)在數(shù)據(jù)庫中
user
這條記錄中的
orgId
沒有被設(shè)置上去。
^_^
,
inverse
的作用這樣可能看的不是很明顯,在下面的一對多中會(huì)加以描述。
u??????
cascade
cascade
的概念和數(shù)據(jù)庫的
cascade
概念是基本一致的,
cascade
的意思形象的來說就是當(dāng)當(dāng)前對象執(zhí)行某操作的情況下,其關(guān)聯(lián)的對象也執(zhí)行
cascade
設(shè)置的同樣的操作。
例如當(dāng)
org.getUsers
的
cascade
設(shè)置為
delete
時(shí),當(dāng)刪除
org
時(shí),相應(yīng)的
users
也同樣被刪除了,但這個(gè)時(shí)候要注意,
org.getUsers
這個(gè)集合是被刪除的
user
的集合,也就是說如果這個(gè)時(shí)候數(shù)據(jù)庫中新增加了一個(gè)
user
給
org
,那么這個(gè)
user
是不會(huì)被刪除的。
cascade
的屬性值詳細(xì)見《
Hibernate reference
》。
3.2.2.1.
?????????
一對一
一對一的關(guān)聯(lián)維護(hù)在實(shí)際項(xiàng)目中使用不多,一對一在Hibernate中可采用兩種方式來構(gòu)成,一種是主鍵關(guān)聯(lián),一種是外鍵關(guān)聯(lián)。
一對一的使用推薦使用主鍵關(guān)聯(lián),具體配置方法請參見《Hibernate Reference》。
3.2.2.2.
?????????
一對多/多對一
一對多/多對一的關(guān)聯(lián)維護(hù)在實(shí)際項(xiàng)目中使用是比較多的,在Hibernate中可采用多種方式來配置一對多的關(guān)聯(lián),如采用Set、List、Bag、Map等,具體在《Hibernate Reference》中都有詳細(xì)說明。
在這里我想說的一點(diǎn)就是關(guān)于inverse的設(shè)置,在一對多的情況下建議將一端的inverse設(shè)為true,而由多端去自動(dòng)維護(hù)關(guān)聯(lián)關(guān)系,為什么這樣做其實(shí)挺容易理解的,假設(shè)org和user為一對多的關(guān)聯(lián),org.getUsers的inverse設(shè)置為false,org.getUsers().add(user);dao.update(org);當(dāng)update的時(shí)候org所關(guān)聯(lián)的所有user的orgId都會(huì)更新一次,可想而知這個(gè)效率,而如果改為在多端維護(hù)(多端設(shè)置為inverse=false),則是這樣:user.setOrg(org);dao.update(user);當(dāng)update的時(shí)候就僅僅是更新user這一條記錄而已。
另外一點(diǎn)就是合理的設(shè)置cascade,這個(gè)要根據(jù)需求來實(shí)際決定。
3.2.2.3.
?????????
多對多
多對多的關(guān)聯(lián)維護(hù)在實(shí)際項(xiàng)目中其實(shí)也是比較多的,盡管在《Hibernate Reference》中認(rèn)為多對多的情況其實(shí)很多時(shí)候都是設(shè)計(jì)造成的。
多對多的關(guān)聯(lián)也同樣可以采用Set、List等多種方式來配置,具體在《Hibernate Reference》中也有詳細(xì)的說明。
多對多的關(guān)聯(lián)維護(hù)上沒有什么需要多說的,在實(shí)踐過程中來看這塊不會(huì)出什么太多問題,唯一需要注意的是合理設(shè)置cascade,這個(gè)要根據(jù)項(xiàng)目的實(shí)際情況而定。
3.3.
實(shí)體的查詢
Hibernate
提供了多種方式來支持實(shí)體的查詢,如對于原有熟悉sql的人可以繼續(xù)使用sql,符合對象語言的對象查詢語句(HQL)以及條件查詢API(Criteria)。
在熟練使用hql或criteria的情況下,我相信你會(huì)覺得Hibernate的查詢方式會(huì)比采用sql的方式更加簡便。
3.3.1.
??????
符合對象語言的查詢語句
Hibernate
提供了一種符合對象語言的查詢語句,稱為
HQL
,這種語句的好處是能夠避免使用
sql
的情況下依賴數(shù)據(jù)庫特征的情況出現(xiàn),同時(shí)它帶來的最大的好處就是我們能夠根據(jù)
OO
的習(xí)慣去進(jìn)行實(shí)體的查詢。
對于
HQL
沒有什么多講的,如果熟悉
sql
的人應(yīng)該也是能夠很快就學(xué)會(huì)
HQL
,而如果不熟悉
sql
的人那也沒關(guān)系,
HQL
的上手是非常容易的,具體請參考《
Hibernate Reference
》。
3.3.2.
??????
占位符式的查詢
占位符式的查詢
(
就是采用
?
替換查詢語句中的變量
)
是在采用
sql
的情況下經(jīng)常使用的一種查詢方式,也是查詢時(shí)推薦使用的一種方式。
Hibernate
中的查詢參數(shù)主要有兩種類型:值類型和實(shí)體類型,值類型就是指一個(gè)切實(shí)的值
(
如
String
、
int
、
List
這些
)
,實(shí)體類型就是一個(gè)具體的實(shí)體,如編寫的
User
、
Organization
等,值類型的查詢和普通
sql
幾乎一樣,而實(shí)體類型的查詢就體現(xiàn)了
Hibernate
的強(qiáng)項(xiàng),
^_^
,可以起到簡化
sql
的作用,并且使得查詢語句更加容易理解。
3.3.2.1.
?????????
值類型
3.3.2.1.1.?????
簡單值
舉例如下:
from User u where u.name=:username and u.yearold=:yearold
這就是一個(gè)常見的簡單值的占位符式的查詢,通過這樣的方式就可以把值注入到參數(shù)中:
query.setParameter(“username”,”bluedavy”);
query.setParameter(“yearold”,25);
同樣,
hibernate
也支持和
sql
完全相同的
?
的方式,那么上面的語句以及注入?yún)?shù)的方式就變?yōu)榱耍?/span>
from User u where u.name=? and u.yearold=?
query.setParameter(0,”bluedavy”);
query.setParameter(1,25);
推薦使用第一種,那樣參數(shù)的意義更容易被理解。
3.3.2.1.2.?????
in
查詢
in
查詢也是經(jīng)常被使用到的一種查詢,在
Hibernate
中表現(xiàn)出來會(huì)稍有不同,不過如果按照對象觀點(diǎn)去看就很容易理解了,例如下面這句:
from User u where u.name in (:usernameList)
在
Hibernate
中通過這樣的方式將值注入到這個(gè)參數(shù)中:
List list=new ArrayList();
list.add(“jerry”);
list.add(“bluedavy”);
query.setParameterList(“usernameList”,list);
在
sql
中通常是組裝一個(gè)由
,
連接的值來構(gòu)成
in
中的參數(shù)值,而在
Hibernate
中則依照對象轉(zhuǎn)化為采用
list
了,
^_^
,是不是更方便些。
3.3.2.2.
?????????
實(shí)體類型
在Hibernate中關(guān)聯(lián)采用的都是對象形式,表現(xiàn)對外就是隱藏了數(shù)據(jù)庫的外鍵的部分,這也就對習(xí)慣使用sql查詢的人帶來一個(gè)問題,因?yàn)闊o法再操作外鍵字段,那么在涉及到關(guān)聯(lián)的實(shí)體的查詢時(shí)應(yīng)該怎么做呢,我把它分為單實(shí)體和實(shí)體集合兩種情況來說說。
3.3.2.2.1.?????
單實(shí)體
單實(shí)體的查詢對應(yīng)到
sql
情況通常是在一對多的情況下通過多端查詢同時(shí)結(jié)合一端的一些過濾條件,在
sql
中通常采用
join
的方式來實(shí)現(xiàn)這個(gè),而在
Hibernate
中要實(shí)現(xiàn)這點(diǎn)就更容易了,舉例如下:
User
和
Organization
是一對多,現(xiàn)在要查詢屬于組織機(jī)構(gòu)名稱為
”Blogjava”
以及用戶年齡大于
20
的用戶:
from User u where u.org.name=:orgname and u.yearold>:yearold
query.setParameter(“orgname”,”Blogjava”);
query.setParameter(“yearold”,20);
可以看到這樣的查詢語句比
sql
更簡單多了,同時(shí)也更容易理解多了。
3.3.2.2.2.?????
實(shí)體集合
實(shí)體集合過濾形式的查詢在實(shí)際的項(xiàng)目中也經(jīng)常會(huì)碰到,仍然用上面的例子,但改為通過
Organization
去查詢:
from Organization org where org.name=:orgname and org.users.yearold>:yearold
是不是比
sql
簡單多了,而且更容易理解呢,
^_^
這個(gè)時(shí)候?qū)ο蠡樵冋Z句的優(yōu)勢就體現(xiàn)出來了,而不用陷入
sql
的那種關(guān)系型的通過外鍵進(jìn)行查詢的方式。
3.3.3.
??????
NamedQuery
NamedQuery
的意思就是指在
PO
的映射文件中定義關(guān)于
PO
的查詢語句,而在應(yīng)用中指需要直接調(diào)用此查詢語句的別名即可,這個(gè)好處非常明顯,使得所有的查詢語句可以統(tǒng)一的進(jìn)行管理,同樣,我們可以在
PO
中通過
javadoc
的方式進(jìn)行定義,這就更方便了,
^_^
操作
NamedQuery
的方法和普通
hql
的方法基本一樣:
session.getNamedQuery(queryname);
其中的
queryname
就是我們定義的查詢語句的別名,一個(gè)
namedQuery
的語句的示例如下:
<
query
name
=
"validate"
><![CDATA[
from User u where u.loginname=:loginname and u.password=:password
]]></
query
>
3.3.4.
??????
Criteria
條件查詢的
API
使得我們可以采用完全對象化的方式進(jìn)行實(shí)體的查詢,而不是通過
hql
的方式,在實(shí)際項(xiàng)目中,使用
hql
的方式更為居多,畢竟寫起來更方便。
關(guān)于
Criteria
的具體介紹請參閱《
Hibernate Reference
》。
3.3.5.
??????
原生
SQL
原生
SQL
不推薦使用,但在某些確實(shí)需要用
sql
的情況下那么
Hibernate
還是支持的,具體見《
Hibernate Reference
》。
四.
????????????
設(shè)計(jì)
獨(dú)立的編寫這個(gè)章節(jié)的原因是希望在采用Hibernate的情況下充分的去發(fā)揮Hibernate的優(yōu)勢,改變我們以關(guān)系形式去做持久層的設(shè)計(jì)的慣性思維,形成以OO的思想去設(shè)計(jì)持久層,所以我非常推薦通過寫PO去生成數(shù)據(jù)表的方式,而不是設(shè)計(jì)表反向?qū)С?span lang="EN-US">PO的形式,當(dāng)然,對于原有的系統(tǒng)那就沒辦法了。
OO
思想中的核心三要素:封裝、繼承和多態(tài),在Hibernate的支持下同樣可以充分發(fā)揮OO的三要素來優(yōu)化持久層的設(shè)計(jì)。
4.1.
封裝
4.1.1.
??????
Component
Hibernate
中有一個(gè)
Component
的概念,這就允許在進(jìn)行持久層設(shè)計(jì)的時(shí)候采用細(xì)粒度級的領(lǐng)域模型進(jìn)行設(shè)計(jì),例如在
User
對象中需要記錄
User
的
firstname
、
lastname
這些信息,而在其他的表中也有這種需求,那么在
Hibernate
中我們就可以把
firstname
、
lastname
組裝為一個(gè)
UserName
對象,作為
Component
放入
User
中,在
user
中就可以變?yōu)椴捎?/span>
user.getUserName.getFristName
的方式來獲取。
Component
對于我們采用對象的封裝概念進(jìn)行持久層設(shè)計(jì)提供了很好的支持,同時(shí)在
Hibernate
中還有
Elements
、
Properties
這些元素,具體請參見《
Hibernate Reference
》。
4.2.
繼承
繼承使得我們可以對持久層中的對象進(jìn)行抽象,類如我們可以形成Person這個(gè)對象,而User、Employee都繼承自這個(gè)對象。
繼承在數(shù)據(jù)庫形式的設(shè)計(jì)中固然也可以實(shí)現(xiàn),但通常不能以對象的觀點(diǎn)去發(fā)揮的淋漓盡致,當(dāng)然不是說以對象的方式去設(shè)計(jì)一定是最好的。
在Hibernate中對于繼承映射到數(shù)據(jù)表有幾種不同的策略,各有適用的不同場合,具體的解釋和說明見《Hibernate Reference》
4.2.1.
??????
單表策略
單表策略很容易理解,就是將類、子類中所有的屬性都放至一張表中,這對于子類屬性不多的情況非常有效。
在
Hibernate
中通常將子類定義為
@hibernate.subclass
的方式來實(shí)現(xiàn)這個(gè)策略。
4.2.2.
??????
每個(gè)子類一張表
每個(gè)子類一張表在
Hibernate
中有幾種實(shí)現(xiàn)方式,
@hibernate.join-subclass
、
@hibernate.join-subclass-key
的組合方式以及
@hibernate.join-subclass
、
@hibernate.discriminator
的組合方式是較常用的兩種方式,第一種方式采用的是主鍵關(guān)聯(lián)方式,第二種方式采用的是
discriminator
字段的關(guān)聯(lián)方式,個(gè)人比較推崇第一種方式。
這種策略適合在子類屬性和父類有較大不同的情況下采用。
4.2.3.
??????
每個(gè)具體類一張表
這種策略適合在類層次結(jié)構(gòu)上有一定數(shù)量的抽象類的情況下使用,同樣有兩種方式,一種是采用顯式多態(tài)的方式,另一種是采用隱式多態(tài)的方式,顯式多態(tài)采用的為
@hibernate.union-subclass
的方式,隱式多態(tài)則采用每個(gè)具體類的
PO
獨(dú)立建表的策略,在它的映射文件中將看不出任何的和接口、抽象類的關(guān)系,同時(shí)對于抽象類,需要指明其
abstract=”true”
。
4.3.
多態(tài)
4.3.1.
??????
查詢
在查詢中很容易體現(xiàn)
Hibernate
對于多態(tài)的支持,如系統(tǒng)有
Person
對象、
User
和
Employee
分別繼承自
Person
,同時(shí)
Person
和
Organization
對象關(guān)聯(lián),這個(gè)時(shí)候我們通過
Organization
獲取其關(guān)聯(lián)的
Person
時(shí)得到的既有可能是
User
,也有可能是
Employee
,
^_^…
五.
????????????
性能
Hibernate
作為ORM工具,從性能上來講帶給了很多人憂慮,但我覺得Hibernate在性能上也許會(huì)帶來少許的降低,但如果對于不能合理設(shè)計(jì)數(shù)據(jù)庫和使用SQL的人來說,我覺得Hibernate反倒能提高性能,除非是在一些特殊的場合,如報(bào)表式的那種查詢推薦繼續(xù)采用JDBC的方式。
Hibernate
在性能提升上其實(shí)有很多種做法,在《Hibernate Reference》中也有專門的提升性能的章節(jié),在這里我提幾點(diǎn)在項(xiàng)目中通常采用的方法。
5.1.
Lazy Load
Lazy Load
是常用的一種提升性能的方法,這個(gè)其實(shí)很容易理解,在不采用lazy load的情況下,Hibernate在獲取一個(gè)PO的時(shí)候,將同時(shí)獲取PO中的屬性、PO中的集合以及集合中對象的屬性、集合,這樣看過去很容易看出,如果對象的關(guān)聯(lián)結(jié)構(gòu)有深層次的話,最后搞不好整個(gè)庫都被加載出來了,而在實(shí)際使用中往往可能只需要用到PO中的一兩個(gè)屬性而已,這點(diǎn)也是之前的ORM產(chǎn)品經(jīng)常被批的一點(diǎn),就是ORM產(chǎn)品不能象sql那樣只獲取需要的東西,^_^,其實(shí)Hibernate在這點(diǎn)上一直就支持,而且支持的還不錯(cuò),在Hibernate 3以后,默認(rèn)的lazy就已經(jīng)設(shè)置為true了,這個(gè)時(shí)候包括po中的屬性都是采用lazy load的方式,只有在調(diào)用到這個(gè)屬性時(shí)才會(huì)從緩存或數(shù)據(jù)庫中加載,當(dāng)然,集合也同樣如此。
在lazy load上推薦不要什么字段都采用lazy load的方式,對于一些基本屬性的字段建議將其lazy設(shè)置為false,而對于一些可能需要消耗內(nèi)存的字段,如clob這樣的字段對象的lazy設(shè)置為true,對于集合則全部設(shè)置為lazy=true。
是否采用Lazy load對系統(tǒng)的性能會(huì)有非常明顯的影響,同時(shí)盡量不要將Detached Object放入Http的session中。
5.1.1.
??????
OSIV
OSIV
:
Open Session In View
,在
B/S
系統(tǒng)中通常采用這種方式來更好的去支持
Lazy load
,意思就是在
View
加載前打開
Session
,在
View
加載完畢后關(guān)閉
Session
的方式,在
Spring
中有
OpenSessionInViewFilter
,可參考或直接使用。
5.2.
Cache
Cache
是在提升系統(tǒng)性能方面常用的方法,在Hibernate中通常有非常好的對于Cache的支持方法,Hibernate中對于Cache有一級緩存和二級緩存的概念,一級緩存是必須的,位于Session部分,二級緩存則不是必須的,由開發(fā)人員自行指定,二級緩存可指定使用何種開源的cache工具,Hibernate 3以后的版本默認(rèn)使用的是Ehcache,也可以切換為Oscache、JbossCache,對我而言最重要的區(qū)別在于對于cluster的支持上。
二級緩存能夠明顯的提高系統(tǒng)的性能,當(dāng)然,同時(shí)也會(huì)更加的消耗內(nèi)存,可以通過配置文件來指定內(nèi)存中能夠加載的最多的元素,這有利于避免消耗過多內(nèi)存。
二級緩存的設(shè)置在Hibernate中非常的簡單,只需要在相應(yīng)的hbm.xml中增加cache元素,指明使用何種策略,如read-only、read-write等,也可以直接在hibernate.cfg.xml中增加class-cache的方式來進(jìn)行全局指定。
5.3.
高效的查詢語句
查詢語句的是否高效對于系統(tǒng)的性能也是會(huì)造成明顯的影響的,為了方便系統(tǒng)性能的調(diào)優(yōu),建議大家對查詢語句進(jìn)行統(tǒng)一管理,如統(tǒng)一采用NamedQuery的方式,在這樣的情況下可以在系統(tǒng)運(yùn)行時(shí)請教數(shù)據(jù)庫專家,由他們來分析系統(tǒng)中的查詢語句的執(zhí)行效率以及提出改進(jìn)策略,而對于開發(fā)人員來講,在查詢語句方面最能夠注意的就是采用占位符式的查詢。
5.3.1.
??????
占位符式的查詢
數(shù)據(jù)庫對于所有的
sql
語 句都要進(jìn)行語法分析,而其分析通常會(huì)受到語句中的大小寫、空格以及參數(shù)不同的影響,在其語法分析器認(rèn)為不同的情況下將再次進(jìn)行分析,這就不可避免的降低了 響應(yīng)的速度,而采用占位符式的查詢則可保證語法分析器只進(jìn)行一次的分析,在參數(shù)不同的情況并不會(huì)出現(xiàn)重復(fù)解析的現(xiàn)象,其次就是要統(tǒng)一查詢語句的編寫風(fēng)格, 包括大小寫、空格這些。
我不是很確定
Hibernate
中對于語句的語法分析,估計(jì)和數(shù)據(jù)庫的這種方式應(yīng)該差不多,不過猜想可能會(huì)更智能一些,
^_^
5.4.
一些配置
在
hibernate.cfg.xml
中的一些配置也會(huì)對性能產(chǎn)生一定的影響,如
jdbc.fetch_size
的設(shè)置等,還有象采用連接池方面的設(shè)置,對于
B/S
應(yīng)用的情況建議盡量采用應(yīng)用服務(wù)器提供的
JNDI
的方式。
5.5.
建議
在性能提升方面從兩方面入手,一是持久層對象的設(shè)計(jì)上,這方面可以參考《
Hibernate Reference
》中提升性能章節(jié)中的一些建議,另一方面則是請教數(shù)據(jù)庫專家,由數(shù)據(jù)庫專家對表結(jié)構(gòu)、查詢語句等進(jìn)行分析來給出改進(jìn)策略,在現(xiàn)有的一個(gè)項(xiàng)目中,竟然有出現(xiàn)
Hibernate
在外鍵上沒建立索引的現(xiàn)象出現(xiàn)?
六.
????????????
測試
6.1.
編寫專門的測試用的配置文件
測試方面也是極度關(guān)心的話題,在測試方面其實(shí)比較簡單,只需要在測試類中采用專門用于測試的配置文件即可,在這個(gè)配置文件中,通過都是采用設(shè)置hbm2ddl.auto屬性為create-drop的方式,也就是在測試類運(yùn)行前創(chuàng)建表,在測試類運(yùn)行后刪除表的策略,在更多的情況下,我們可以采用in-memory的數(shù)據(jù)庫的方式,如hsql,當(dāng)然,有些時(shí)候則需要和實(shí)際運(yùn)行環(huán)境一致,那么就需要采用建立專門的測試庫的方式,避免測試數(shù)據(jù)和運(yùn)行數(shù)據(jù)的相互影響。
七.
????????????
企業(yè)應(yīng)用開發(fā)
事務(wù)和并發(fā)是企業(yè)應(yīng)用開發(fā)中非常關(guān)注的兩個(gè)話題,在《Hibernate Reference》中提供了詳細(xì)的方案,在這里我就簡單的說說。
7.1.
事務(wù)
事務(wù)是企業(yè)應(yīng)用開發(fā)中非常重視的一點(diǎn),而在Hibernate中操作此部分和sql方式?jīng)]有什么很大的區(qū)別,可以通過session主動(dòng)去獲取Transaction來實(shí)現(xiàn)事務(wù)控制,同時(shí)也可以交由應(yīng)用服務(wù)器提供的JTA來實(shí)現(xiàn)事務(wù)控制。
在事務(wù)這個(gè)級別上如果有更高的要求,建議采用Spring的事務(wù)框架。
7.2.
并發(fā)
在并發(fā)方面多采用鎖策略,鎖策略和數(shù)據(jù)庫基本相同,同樣是樂觀鎖和悲觀鎖兩種策略,樂觀鎖策略在Hibernate中推薦使用version或timestamp來實(shí)現(xiàn),具體覆蓋方式則需要根據(jù)應(yīng)用而定,如是采用最新的修改的覆蓋還是采用版本沖突策略等,悲觀鎖策略則通過指定對象的鎖方式,如LockMode.READ,引用《Hibernate Reference》中的一段話:
“用戶其實(shí)并不需要花很多精力去擔(dān)心鎖定策略的問題。通常情況下,只要為JDBC連接指定一下隔離級別,然后讓數(shù)據(jù)庫去搞定一切就夠了。然而,高級用戶有時(shí)候希望進(jìn)行一個(gè)排它的悲觀鎖定,或者在一個(gè)新的事務(wù)啟動(dòng)的時(shí)候,重新進(jìn)行鎖定。Hibernate總是使用數(shù)據(jù)庫的鎖定機(jī)制,從不在內(nèi)存中鎖定對象!
如果數(shù)據(jù)庫不支持用戶設(shè)置的鎖定模式,Hibernate將使用適當(dāng)?shù)奶娲J?,這一點(diǎn)可以確保應(yīng)用程序的可移植性。”。
用戶可通過幾種方式來指定鎖定模式:
u??????
Session.load()
的時(shí)候指定鎖定模式LockMode;
u??????
Session.lock()
;
u??????
Query.setLockMode()
。
八.
????????????
相關(guān)書籍
Hibernate
上手并不難,但要真正的用好它確實(shí)不是件容易的事,有些書籍能夠很好的幫我們快速的提供解決思路和解決方案,而這些書籍我們也應(yīng)該常備,以方便自己在有些問題上的解答。
同時(shí),我一直堅(jiān)持的觀點(diǎn),一種開源框架通常帶來的不僅僅是開發(fā)、使用上的改變,帶來的最大的改變?nèi)匀皇窃谠O(shè)計(jì)層次上的,設(shè)計(jì)上能否充分的發(fā)揮開源框架的優(yōu)勢才是最為重要的。
8.1.
《Hibernate Reference》
這本沒什么說的,必讀書籍,也許在讀的時(shí)候很多東西你不會(huì)覺得什么,但當(dāng)碰到一些確定方向的問題時(shí),可以通過此書快速的查找到相應(yīng)的解決方案,感謝Redsaga組織的翻譯工作,使得我們可以有中文版可看。
目前版本(Hibernate 3.1.2)的下載地址:
http://www.redsaga.com/hibernate-ref/3.1.2/zh-cn/pdf/hibernate_reference.pdf
8.2.
《Hibernate in action》
In action
系列的書籍也沒啥多說的,強(qiáng)烈推薦看看,盡管現(xiàn)在看起來版本有些老了,但里面很多的實(shí)踐思想仍然是非常值得學(xué)習(xí)的,網(wǎng)上應(yīng)該有很多電子版下載的地方。
8.3.
《深入淺出Hibernate》
這本書想必大家也聽聞了不少,簡稱白皮書,^_^,是夏昕、曹曉剛以及唐勇三位大師的大作。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=656038