Hibernate4實戰 之第七部分:最佳實踐 – JAVA編程語言程序開發技術文章

設計細顆粒度的持久類並且使用<component>來實現映射。
例如使用一個Address持久類來封裝 street, suburb, state, postcode. 這將有利於代碼重用和簡化代碼重構(refactoring)的工作。
對持久類聲明標識符屬性( identifier properties)。
Hibernate中標識符屬性是可選的,不過有很多原因來說明你應該使用標識符屬性。我們建議標識符應該是“人造”的(自動生成,不涉及業務含義)。
使用自然鍵(natural keys)標識
對所有的實體都標識出自然鍵,用<natural-id>進行映射。實現equals()和hashCode(),在其中用組成自然鍵的屬性進行比較。
為每個持久類寫一個映射文件
不要把所有的持久類映射都寫到一個大文件中。把 com.eg.Foo 映射到com/eg/Foo.hbm.xml中, 在團隊開發環境中,這一點顯得特別有意義。
把映射文件作為資源加載
把映射文件和他們的映射類放在一起進行部署。
考慮把查詢字符串放在程序外面
如果你的查詢中調用瞭非ANSI標準的SQL函數,那麼這條實踐經驗對你適用。把查詢字符串放在映射文件中可以讓程序具有更好的可移植性。
使用綁定變量
就像在JDBC編程中一樣,應該總是用占位符"?"來替換非常量值,不要在查詢中用字符串值來構造非常量值!更好的辦法是在查詢中使用命名參數。
不要自己來管理JDBC connections
Hibernate允許應用程序自己來管理JDBC connections,但是應該作為最後沒有辦法的辦法。如果你不能使用Hibernate內建的connections providers,那麼考慮實現自己來實現org.hibernate.connection.ConnectionProvider
考慮使用用戶自定義類型(custom type)
假設你有一個Java類型,來自某些類庫,需要被持久化,但是該類沒有提供映射操作需要的存取方法。那麼你應該考慮實現org.hibernate.UserType接口。這種辦法使程序代碼寫起來更加自如,不再需要考慮類與Hibernate type之間的相互轉換。
在性能瓶頸的地方使用硬編碼的JDBC
在系統中對性能要求很嚴格的一些部分,某些操作也許直接使用JDBC會更好。但是請先確認這的確是一個瓶頸,並且不要想當然認為JDBC一定會更快。如果確實需要直接使用JDBC,那麼最好打開一個 Hibernate Session 然後從 Session獲得connection,按照這種辦法你仍然可以使用同樣的transaction策略和底層的connection provider。
理解Session清洗( flushing)
Session會不時的向數據庫同步持久化狀態,如果這種操作進行的過於頻繁,性能會受到一定的影響。有時候你可以通過禁止自動flushing,盡量最小化非必要的flushing操作,或者更進一步,在一個特定的transaction中改變查詢和其它操作的順序。
在三層結構中,考慮使用托管對象(detached object)
當使用一個servlet / session bean 類型的架構的時候, 你可以把已加載的持久對象在session bean層和servlet / JSP 層之間來回傳遞。使用新的session來為每個請求服務,使用 Session.merge() 或者Session.saveOrUpdate()來與數據庫同步。
在兩層結構中,考慮使用長持久上下文(long persistence contexts).
為瞭得到最佳的可伸縮性,數據庫事務(Database Transaction)應該盡可能的
短。但是,程序常常需要實現長時間運行的“應用程序事務(Application
Transaction)”,包含一個從用戶的觀點來看的原子操作。這個應用程序事務
可能跨越多次從用戶請求到得到反饋的循環。用脫管對象(與session脫離的對
象)來實現應用程序事務是常見的。或者,尤其在兩層結構中,把Hibernate
Session從JDBC連接中脫離開,下次需要用的時候再連接上。絕不要把一個
Session用在多個應用程序事務(Application Transaction)中,否則你的數據
可能會過期失效。
不要把異常看成可恢復的
這一點甚至比“最佳實踐”還要重要,這是“必備常識”。當異常發生的時
候,必須要回滾 Transaction ,關閉Session。如果你不這樣做的話,
Hibernate無法保證內存狀態精確的反應持久狀態。尤其不要使用
Session.load()來判斷一個給定標識符的對象實例在數據庫中是否存在,應該
使用Session.get()或者進行一次查詢.
對於關聯優先考慮lazy fetching
謹慎的使用主動抓取(eager fetching)。對於關聯來說,若其目標是無法在第二級緩存中完全緩存所有實例的類,應該使用代理(proxies)與/或具有延遲加載屬性的集合(lazy collections)。若目標是可以被緩存的,尤其是緩存的命中率非常高的情況下,應該使用lazy="false",明確的禁止掉eager fetching。如果那些特殊的確實適合使用join fetch 的場合,請在查詢中使用left join fetch。
使用open session in view模式,或者執行嚴格的裝配期(assembly phase)策略來避免再次抓取數據帶來的問題
Hibernate讓開發者們擺脫瞭繁瑣的Data Transfer Objects (DTO)。在傳統的EJB結構中,DTO有雙重作用:首先,他們解決瞭entity bean無法序列化的問題;其次,他們隱含地定義瞭一個裝配期,在此期間,所有在view層需要用到的數據,都被抓取、集中到瞭DTO中,然後控制才被裝到表示層。Hibernate終結瞭第一個作用。然而,除非你做好瞭在整個渲染過程中都維護一個打開的持久化上下文(session)的準備,你仍然需要一個裝配期(想象一下,你的業務方法與你的表示層有嚴格的契約,數據總是被放置到托管對象中)。這並非是Hibernate的限制!這是實現安全的事務化數據訪問的基本需求。
考慮把Hibernate代碼從業務邏輯代碼中抽象出來
把Hibernate的數據存取代碼隱藏到接口(interface)的後面,組合使用DAO和Thread Local Session模式。通過Hibernate的UserType,你甚至可以用硬編碼的JDBC來持久化那些本該被Hibernate持久化的類。 (該建議更適用於規模足夠大應用軟件中,對於那些隻有5張表的應用程序並不適合。)不要用怪異的連接映射
多對多連接用得好的例子實際上相當少見。大多數時候你在“連接表”中需要保存額外的信息。這種情況下,用兩個指向中介類的一對多的連接比較好。實際上,我們認為絕大多數的連接是一對多和多對一的,你應該謹慎使用其它連接風格,用之前問自己一句,是否真的必須這麼做。
偏愛雙向關聯
單向關聯更加難於查詢。在大型應用中,幾乎所有的關聯必須在查詢中可以雙向導航。
作者:jinnianshilongnian

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。