在本文中我們介紹並比較兩種最流行的開源持久框架:iBATIS和Hibernate,我們還會討論到Java Persistence API(JPA)。我們介紹每種解決方案並討論其所規定的品質,以及在廣泛的應用場景中其各自的長處和缺點。然后我們會基於諸如性能、移植性、復雜性以及對數據模型改變的適應性等因素來比較iBATIS、Hibernate和JPA。
如果你是一個剛起步的Java程序員,新接觸持久性概念的話,那么就把閱讀此文當作是接受一次這一主題以及大部分流行的開源持久性解決方案的啟蒙。如果你對這三種解決方案都很熟悉,並且只想要一個簡單的比較的話,那么你會在“比較持久化技術”一節中找到相應的內容。
理解持久性
持久性(persistence)是數據的一個屬性,其確保即使是在應用的生命周期之外數據也是可用的。對於像Java這樣的面向對象語言來說,持久性確保了即使是在創建對象的應用停止執行之后對象的狀態仍是可訪問的。
存在多種實現持久性的方法。傳統的解決這一問題的方法是使用文件系統來把需要的信息存儲在平面文件(flat file)中。這一方法很難用來管理大量的數據,因為數據分布在不同的文件中。使用平面文件系統的話維護數據的一致性也是一個問題,因為相同的信息可能會被重復放在各個文件中。在平面文件中查找數據很耗時,特別是如果這些文件還未排序的話。還有,文件系統對並發訪問的支持有限,因為它們不能確保數據的完整性。基於上述種種原因,在尋求持久性時,文件系統並不被視為一個良好的數據存儲解決方案。
當前最常見的方法是使用數據庫,其充當巨大量數據的存儲庫。存在許多種類型的數據庫:關系型的、層次結構型的、網絡型的、面向對象型的等等。這些數據庫,以及它們的數據庫管理系統(DBMS),不僅提供持久性能力,而且管理其所持久的信息。關系數據庫是最被廣泛使用的類型,關系數據庫中的數據被建模成一組相互關聯的表。
企業級應用的出現普及了n層架構,其目的是通過把表現、業務和數據庫相關代碼分離到應用的不同層級(或是層面)中來提升可維護性。分離了業務邏輯和數據庫代碼的層面即是持久層,其保持了應用相對於底層的數據庫技術的獨立性。適當的位置上有了這一強健的層面,開發者就不再需要操心數據的持久性。持久層封裝了存儲和檢索關系型數據庫中的數據的方式。
Java應用傳統上使用JDBC(Java Database Connectivity)API來把數據持久到關系數據庫中。JDBC API使用SQL語句來完成創建(create)、讀取(read)、更新(update)和刪除(delete)(CRUD)操作。JDBC代碼內嵌在Java類中——換句話說,這類代碼與業務邏輯緊密耦合在一起。這類代碼還在很大程度上依賴於SQL,而SQL並非是跨數據庫的標准;這使得從一種數據庫移植到另一種數據庫變得困難起來。
關系數據庫技術強調的是數據及其之間的關系,而用於Java中的面向對象范式卻並非關注數據本身,而是關注執行於數據之上的操作。因此,當這兩種技術需要攜手合作時,就會存在利益沖突。而且,關系數據庫並不能滿足繼承、多態及關聯這些面向對象編程概念。當Java應用中的用戶定義的數據類型被映射到關系數據庫上時,由這一失配導致的另一個問題就出現了,因為后者並沒有提供所需的類型支持。
對象關系映射
對象關系映射(object-relational mapping,ORM)已成為了有時被稱作對象關系阻抗失配(impedance mismatch)的這一問題的一個解決方案。ORM是一種透明地把應用對象持久到關系數據庫中的表的技術。ORM的行為就像是一個虛擬的數據庫,對用戶隱藏了底層的數據庫架構。ORM提供功能來執行完整的CRUD操作並鼓勵面向對象的查詢。ORM還支持元數據映射以及在應用的事務管理方面提供幫助。
舉個例子有助於說明ORM是如何工作的。考慮一個需要持久到數據庫中的簡單的Car對象,領域模型中的這一Car對象是數據模型中的CAR表的表現形式。Car對象的屬性派生自CAR表的各列。在Car類和CAR表之間存在一個直接映射。
存在許多開源的ORM工具,其中包括Hibernate、iBATIS SQL Maps以及Java Ultra-Lite Persistence等。這些工具大多數是提供Java應用和數據庫之間的抽象層的持久性框架。持久性框架把應用領域中的對象映射成需要持久在數據庫中的數據,這些映射可使用XML文件或是元數據注解(后者作為Java1.5的組成部分被引入到語言中)來定義。持久性框架的目的是分離數據庫相關代碼和應用代碼(即業務邏輯),從而提高應用的靈活性。持久性框架通過提供一個持久性邏輯的包裝器來簡化開發過程。
完成了持久性的基本介紹之后,我們就做好了繼續討論兩種最流行的開源持久框架iBATIS和Hibernate的准備。我們還會介紹Java Persistence API,並討論這三種解決方案在各種應用場景中的優勢和弱點。
何時使用iBATIS
iBATIS最好是用在你需要全面地控制SQL的時候,在需要對SQL查詢做微調的時候也很有用。當你在應用和數據庫設計兩方面都有完全的控制權的時候,就不應該使用iBATIS,因為在這樣的情況下,應用可能會做出修改以適應數據庫,或是反過來。在這種情形中,你可以構建一個完全的對象-關系應用,其他的ORM工具更適於使用,因為iBATIS較為以SQL為中心,其通常被稱作反轉的——功能齊全的ORM工具生成SQL,而iBATIS直接使用SQL。iBATIS也不適合於非關系型的數據庫,因為這類數據庫不支持事務和其他iBATIS用到的鍵特性。
何時使用Hibernate
Hibernate最適合用來作為端到端的OR映射的手段。其提供了一個完整的ORM解決方案,但但是不會讓你控制查詢。對於那些對應用和數據庫兩者都有完全的控制權的情況來說,Hibernate是一種理想的解決方案。在這類情況中,你可以修改應用來適用數據庫,反之亦然,在這些情況下你可以使用Hibernate來構建一個全對象-關系應用。對於不太熟悉SQL的面向對象編程者來說,Hibernate是最佳選擇。
何時使用JPA
JPA應該用在需要標准的基於Java的持久性解決方案的時候。JPA支持繼承和多態這兩種面向對象編程特性。JPA的缺點是其需要一個實現了其自身的提供程序。這些供應商特有的工具還提供了某些並未定義成JPA規范組成部分的特性,其中一個這樣的特性是緩存支持,該功能並未在JPA中做明確定義,但其中一個最流行的實現了JPA的框架Hibernate對這一功能提供了很好的支持。
此外,JPA被定義成只能在關系數據庫上工作。如果你的持久化解決方案需要擴展到其他類型的數據存儲上,比如XML數據庫上的話,則JPA就不能夠用來解決你的持久性問題了。
比較持久化技術
現在你已經分析了三種不同的持久化機制及其運作方式。這些框架中的每一種都有自己的優點和缺點。讓我們來考慮幾個參數,這些參數可幫助你確定其中滿足你需求的最佳可行方案。
簡易性
在許多應用的開發中,時間是主要的制約因素,特別是當團隊成員需要經培訓來使用某種特定框架的時候。在這類情形中,iBATIS是最好的選擇,該框架是三種框架中最簡單的,因為它僅需SQL方面的知識就夠了。
完整的ORM解決方案
像Hibernate和JPA一類的傳統的ORM解決方案應該用來作為一種完全的對象-關系映射手段。Hibernate和JPA直接把Java對象映射到數據庫表上,而iBATIS則是把Java對象映射到SQL查詢的結果上。在某些應用中,領域模型中的對象是根據業務邏輯來設計的,可能不完全與數據模型匹配,在這種情況下,iBATIS是合適的選擇。
對SQL的依賴
總是會存在精通Java的人和更信任SQL的人這樣的一種划分,對於一個熟練的Java程序員來說,他想使用一個無需與SQL有太多交互的持久性框架,那么Hibernate是最好的選擇,因為它會在運行時生成高效率的SQL查詢。但是,如果你想要使用存儲過程來對數據庫查詢做各方面的控制的話,則iBATIS是推薦的解決方案。JPA還可通過EntityManager的createNativeQuery()方法來支持SQL。
支持的查詢語言
iBATIS大力支持SQL,而Hibernate和JPA則是使用它們自己的查詢語言(分別是HQL和JPQL),這些語言與SQL類似。
性能
一個應用要成功的話需要具備良好的性能。Hibernate通過提供緩存設施來提高性能,這些緩存設施有助於更快地從數據庫中檢索數據。iBATIS使用SQL查詢,這些查詢可通過微調來獲得更佳性能。JPA的性能則取決於供應商的實現,根據每個應用的特有情況做選擇。
跨不同數據庫的移植性
有時候,你需要改變應用使用的關系數據庫,如果你使用Hibernate來作為持久化解決方案的話,那么這一問題很容易解決,因為Hibernate在配置文件中使用了一個數據庫方言屬性。從一個數據庫移植到另一個數據庫上僅是把dialect屬性修改成適當值的事。Hibernate使用這一屬性來作為生成特定於某種給定數據庫的SQL代碼的指南。
如前所述,iBATIS要求你編寫自己的SQL代碼,因此,iBATIS應用的可移植性取決於這些SQL。如果查詢是使用可移植的SQL編寫的話,那么iBATIS也是可在不同的關系數據庫之間做移植的。另一方面,JPA的移植性則取決於其正在使用的供應商實現。JPA是可在不同的實現之間做移植的,比如Hibernate和TopLink Essentials之間。因此,如果應用沒有用到某些提供商特有的功能特性的話,那么移植性就不是什么大問題。
社區支持和文檔
在這方面,Hibernate明顯是個贏家。存在許多以Hibernate為焦點的論壇,在這些論壇中社區成員都會積極地回答各種問題。關於這一點,iBATIS和JPA正慢慢趕上。
跨非Java平台的移植性
iBATIS支持.Net和Ruby on Rails。Hibernate以NHibernate的形式為.Net提供了一個持久性解決方案。JPA,作為特定於Java的API,顯然並不支持任何的非Java平台。
表1給出了這一比較的一個總結。
表1. 持久性解決方案比較
特性 |
iBATIS |
Hibernate |
JPA |
簡易性 |
優 |
良 |
良 |
完整的ORM解決方案 |
一般 |
優 |
優 |
對數據模型改變的適應性 |
良 |
一般 |
一般 |
復雜性 |
優 |
一般 |
一般 |
對SQL的依賴 |
良 |
一般 |
一般 |
性能 |
優 |
優 |
不適用* |
跨不同關系數據庫的移植性 |
一般 |
優 |
不適用* |
非Java平台的移植性 |
優 |
良 |
不支持 |
社區支持和文檔 |
一般 |
良 |
良 |
*JPA對這些特性的支持取決於持久性提供程序,最終的結果可能會視情況各異。
結論
iBATIS、Hibernate和JPA是用於把數據持久到關系數據庫中的三種不同的機制,每種都有着自己的優勢和局限性。iBATIS不提供完整的ORM解決方案,也不提供任何的對象和關系模型的直接映射。不過,iBATIS給你提供了對查詢的全面控制權。Hibernate提供了一個完整的ORM解決方案,但不提供對查詢的控制權。Hibernate非常的受歡迎,有一個龐大而活躍的社區為新用戶提供支持。JPA也提供一個完整的ORM解決方案,並提供對諸如繼承和多態一類的面向對象編程特性的支持,不過它的性能則取決於持久性提供程序。
某個特定持久性機制的選擇事關所有功能特性的權衡,這些特性在本文的比較章節中都做了討論。對於大部分的開發者來說,需要根據是否要求對應用的SQL做全面控制、是否需要自動生成SQL,或僅是想要一個易於編程的完整的ORM解決方案等各方面的考慮來做決定。