<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    空間站

    北極心空

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

    一. ????????????

    在實(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ā)的效率,通常都需要使用一些輔助工具,如xdocletmiddlegen等。

    盡管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 ToolsEclipse 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的屬性來決定是采用threadjta或自定義的方式來產(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以上版本還提供了對于MapXML的方式的持久的支持,就更方便了,在項(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、BagMap等,具體在《Hibernate Reference》中都有詳細(xì)說明。

    在這里我想說的一點(diǎn)就是關(guān)于inverse的設(shè)置,在一對多的情況下建議將一端的inverse設(shè)為true,而由多端去自動(dòng)維護(hù)關(guān)聯(lián)關(guān)系,為什么這樣做其實(shí)挺容易理解的,假設(shè)orguser為一對多的關(guān)聯(lián),org.getUsersinverse設(shè)置為falseorg.getUsers().add(user);dao.update(org);當(dāng)update的時(shí)候org所關(guān)聯(lián)的所有userorgId都會(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)。

    在熟練使用hqlcriteria的情況下,我相信你會(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放入Httpsession中。

    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-onlyread-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中推薦使用versiontimestamp來實(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

    posted on 2006-12-22 14:40 蘆葦 閱讀(442) 評論(0)  編輯  收藏 所屬分類: Hibernate
    主站蜘蛛池模板: 国产午夜无码视频免费网站| 国产成人久久AV免费| 18禁亚洲深夜福利人口| 亚洲国产aⅴ成人精品无吗| 亚洲国产精品一区二区三区在线观看| 亚洲成人网在线观看| 亚洲一区中文字幕| 亚洲人成网国产最新在线| 亚洲乱码中文字幕在线| 色噜噜噜噜亚洲第一| 新最免费影视大全在线播放| 一级做a爱片特黄在线观看免费看| 免费无码午夜福利片69| 国产精品成人69XXX免费视频| 99麻豆久久久国产精品免费| 免费在线中文日本| 成人免费激情视频| 午夜视频在线观看免费完整版| 情侣视频精品免费的国产| 亚洲XX00视频| 亚洲精品无码不卡在线播放HE| 久久精品亚洲综合一品| 亚洲一区二区三区免费在线观看 | 免费人成视频在线| 精品久久久久久久免费人妻| 免费人成在线观看播放国产| 亚洲中文字幕无码永久在线| 亚洲色图在线播放| 亚洲真人无码永久在线观看| 青娱乐在线视频免费观看| 中文字幕乱码一区二区免费| **一级毛片免费完整视| 四虎成人精品一区二区免费网站| 亚洲福利视频一区二区| 亚洲国产成人久久精品动漫 | 亚洲国产精品久久66| 亚洲av日韩av无码av| 久久亚洲中文无码咪咪爱| 中国国产高清免费av片| 九九精品免费视频| 久久久久亚洲AV成人网人人网站|