由於項目須要選擇數據持久化框架,看了一下主要幾個流行的和不流行的框架,對於複雜業務系統,最終的結論是,JOOQ是整體上最好的,惋惜不是徹底免費,最終選擇JDBC Template。java
Hibernate和Mybatis是使用最多的兩個主流框架,而JOOQ、Ebean等小衆框架則知道的人很少,但也有不少獨特的優勢;而JPA則是一組Java持久層Api的規範,Spring Data JPA是JPA Repository的實現,原本和Hibernate、Mybatis、JOOQ之類的框架不在同一個層次上,但引入Spring Data JPA之類框架以後,咱們會直接使用JPA的API查詢更新數據庫,就像咱們使用Mybatis同樣,因此這裏也把JPA和其餘框架放在一塊兒進行比較。程序員
一樣,JDBC和其餘框架也在同一層次,位於全部持久框架的底層,但咱們有時候也會直接在項目中使用JDBC,而Spring JDBC Template部分消除了使用JDBC的繁瑣細節,下降了使用成本,使得咱們更加願意在項目中直接使用JDBC。sql
1、SQL封裝和性能數據庫
在使用Hibernate的時候,咱們查詢的是POJO實體類,而再也不是數據庫的表,例如hql語句 select count(*) from User,裏面的User是一個Java類,而不是數據庫表User。這符合ORM最初的理想,ORM認爲Java程序員使用OO的思惟方式,和關係數據庫的思惟方式差距巨大,爲了填補對象和關係思惟方式的鴻溝,必須作一個對象到關係的映射,而後在Java的對象世界中,程序員可使用純的對象的思惟方式,查詢POJO對象,查詢條件是對象屬性,再也不須要有任何表、字段等關係的概念,這樣java程序員就更容易作持久層的操做。編程
JPA能夠視爲Hibernate的兒子,也繼承了這個思路,把SQL完全封裝起來,讓Java程序員看不到關係的概念,用純的面向對象思想,從新創造一個新的查詢語言代替sql,好比hql,還有JPQL等。支持JPA的框架,例如Ebean都屬於這種類型的框架。安全
但封裝SQL,使用另外一種純的面向對象查詢語言代替sql,真的可以讓程序員更容易實現持久層操做嗎?MyBatis的流行證實了事實並不是如此,至少在大多數狀況下,使用hql並不比使用sql簡單。首先,從不少角度上看,hql/JPQL等語言更加複雜和難以理解;其次就是性能上明顯下降,速度更慢,內存佔用巨大,並且還很差優化。最爲惱火的是,當關系的概念被替換爲對象的概念以後,查詢語言的靈活性變得不好,表達能力也比sql弱不少。寫查詢語句的時候受到各類各樣的限制,一個典型的例子就是多表關聯查詢。框架
無論是hibernate仍是jpa,表之間的鏈接查詢,被映射爲實體類之間的關聯關係,這樣,若是兩個實體類之間沒有(實現)關聯關係,你就不能把兩個實體(或者表)join起來查詢。這是很惱火的事情,由於咱們不少時候並不須要顯式定義兩個實體類之間的關聯關係就能夠實現業務邏輯,若是使用hql,只是爲了join咱們就必須在兩個實體類之間添加代碼,並且還不能逆向工程,若是表裏面沒有定義外鍵約束的話,逆向工程會把咱們添加的關聯代碼抹掉。函數
MyBatis則是另一種類型的持久化框架,它沒有封裝SQL也沒有建立一種新的面相對象的查詢語言,而是直接使用SQL做爲查詢語言,只是把結果填入POJO對象而已。使用sql並不比hql和JPQL困難,查詢速度快,能夠靈活使用任意複雜的查詢只要數據庫支持。從SQL封裝角度上看,MyBatis比Hibernate和JPA成功,SQL本不應被封裝和隱藏,讓Java程序員使用SQL既不麻煩也更容易學習和上手,這應該是MyBatis流行起來的重要緣由。性能
輕量級持久層框架JOOQ也和MyBatis同樣,直接使用SQL做爲查詢語言,比起MyBatis,JOOQ雖然知名度要低得多,但JOOQ不但和MyBatis同樣能夠利用SQL的靈活性和高效率,經過逆向工程,JOOQ還能夠用Java代碼來編寫SQL語句,利用IDE的代碼自動補全功能,自動提示表名和字段名,減小程序員記憶負擔,還能夠在元數據發生變化時發生編譯錯誤,提示程序員修改相應的SQL語句。學習
Ebean做爲一種基於JPA的框架,它也使用JPQL語言進行查詢,多數狀況下會讓人很惱火。但聽說Ebean不排斥SQL,能夠直接用SQL查詢,也能夠用相似JOOQ的DSL方式在代碼中構造SQL語句(仍是JPQL語句?),但沒用過Ebean,因此具體細節不清楚。
JDBC Template就不用說了,它根本沒作ORM,固然是純SQL查詢。利用Spring框架,能夠把JDBC Template和JPA結合起來使用,在JPA很差查詢的地方,或者效率低很差優化的地方使用JDBC,緩解了Hibernate/JPA封裝SQL形成的麻煩,但我仍沒看到任何封裝SQL的必要性,除了給程序員帶來一大堆麻煩和學習負擔以外,沒有太明顯的好處。
2、DSL和變化適應性
爲了實現複雜的業務邏輯,不管是用SQL仍是hql或者JPQL,咱們都不得不寫不少簡單的或者複雜的查詢語句,ORM沒法減小這部分工做,最可能是用另外一種面向對象風格的語言去表達查詢需求,如前所述,用面向對象風格的語言不見得比SQL更容易。一般業務系統中會有不少表,每一個表都有不少字段,即使是編寫最簡單的查詢語句也不是一件容易的事情,須要記住數據庫中有哪些表,有哪些字段,記住有哪些函數等。寫查詢語句不少時候成爲一件頭疼的事情。
QueryDSL、JOOQ、Ebean甚至MyBatis和JPA都設計一些特性,幫助開發人員編寫查詢語句,有人稱之爲「DSL風格數據庫編程」。最先實現這類功能的多是QueryDSL,把數據庫的表結構逆向工程爲java的類,而後可讓java程序員可以用java的語法構造出一個複雜的查詢語句,利用IDE的代碼自動補全功能,能夠自動提示表名、字段名、查詢語句的關鍵字等,很成功的簡化了查詢語句的編寫,免除了程序員記憶各類名字、函數和關鍵字的負擔。
QueryDSL有不少版本,但用得多的是QueryDSL JPA,能夠幫助開發人員編寫JPQL語句,如前所述,JPQL語句有不少侷限不如SQL靈活高效。後來的JOOQ和Ebean,基本上繼承了QueryDSL的思路,Ebean基本上仍是JPA風格的ORM框架,雖然也支持SQL,但不清楚其DSL特性是否支持SQL語句編寫,在官網上看到的例子都是用於構造JPQL語句。
這裏面最成功的應該是JOOQ,和QueryDSL不一樣,JOOQ的DSL編程是幫助開發人員編寫SQL語句,拋棄累贅的ORM概念,JOOQ這個功能很是輕小,很是容易學習和使用,同時性能也很是好,不像QueryDSL和Ebean,須要瞭解複雜的JPA概念和各類奇異的限制,JOOQ編寫的就是普通的SQL語句,只是把查詢結果填充到實體類中(嚴格說JOOQ沒有實體類,只是自動生成的Record對象),JOOQ甚至不必定要把結果轉換爲實體類,可讓開發人員按照字段取得結果的值,相對於JDBC,JOOQ會把結果值轉換爲合適的Java類型,用起來比JDBC更簡單。
傳統主流的框架對DSL風格支持得不多,Hibernate裏面基本上沒有看到有這方面的特性。MyBatis提供了"SQL語句構建器"來幫助開發人員構造SQL語句,但和QueryDSL/JOOQ/Ebean差不少,不能提示表名和字段名,語法也顯得累贅不像SQL。
JPA給人的印象是複雜難懂,它的MetaModel Api繼承了特色,MetaModel API+Criteria API,再配合Hibernate JPA 2 Metamodel Generator,讓人有點QueryDSL JPA的感受,只是繞了一個大大的彎,疊加了好幾層技術,最後勉強實現了QueryDSL JPA的簡單易懂的功能。不少人不推薦JPA+QueryDSL的用法,而是推薦JPA MetaModel API+Criteria API+Hibernate JPA 2 Metamodel Generator的用法,讓人很難理解,也許是由於這個方案是純的標準的JPA方案。
數據庫DSL編程的另外一個主要賣點是變化適應性強,數據庫表結構在開發過程當中一般會頻繁發生變化,傳統的非DSL編程,字段名只是一個字符串,若是字段名或者類型改變以後,查詢語句沒有相應修改,編譯不會出錯,也容易被開發人員忽略,是bug的一個主要來源。DSL編程裏面,字段被逆向工程爲一個java類的屬性,數據庫結構改變以後,做爲java代碼一部分的查詢語句會發生編譯錯誤,提示開發人員進行修改,能夠減小大量bug,減輕測試的負擔,提升軟件的可靠性和質量。
3、跨數據庫移植
Hibernate和JPA使用hql和JPQL這類數據庫無關的中間語言描述查詢,能夠在不一樣數據庫中無縫移植,移植到一個SQL有巨大差異的數據庫一般不須要修改代碼或者只須要修改不多的代碼。Ebean若是不使用原生SQL,而是使用JPA的方式開發,也能在不一樣數據庫中平滑的移植。
MyBatis和JOOQ直接使用SQL,跨數據庫移植時都不免要修改SQL語句。這方面MyBatis比較差,只有一個動態SQL提供的特性,對於不一樣的數據庫編寫不一樣的sql語句。
JOOQ雖然沒法像Hibernate和JPA那樣無縫移植,但比MyBatis好不少。JOOQ的DSL很大一部分是通用的,例如分頁查詢中,Mysql的limit/offset關鍵字是很方便的描述方式,但Oracle和SQLServer的SQL不支持,若是咱們用JOOQ的DSL的limit和offset方法構造SQL語句,不修改移植到不支持limit/offset的Oracle和SQLServer上,咱們會發現這些語句還能正常使用,由於JOOQ會把limit/offset轉換成等價的目標數據庫的SQL語句。JOOQ根據目標數據庫轉換SQL語句的特性,使得在不一樣數據庫之間移植的時候,只須要修改不多的代碼,明顯優於MyBatis。
JDBC Template應該最差,只能儘可能使用標準sql語句來減小移植工做量。
4、安全性
通常來講,拼接查詢語句都會有安全隱患,容易被sql注入攻擊。不管是jdbc,仍是hql/JPQL,只要使用拼接的查詢語句都是不安全的。對於JDBC來講,使用參數化的sql語句代替拼接,能夠解決問題。而JPA則應該使用Criteria API解決這個問題。
對於JOOQ之類的DSL風格框架,最終會被render爲參數化的sql,天生免疫sql注入攻擊。Ebean也支持DSL方式編程,也一樣免疫sql注入攻擊。
這是由於DSL風格編程參數化查詢比拼接字符串查詢更簡單,沒人會拼接字符串。而jdbc/hql/JPQL拼接字符串有時候比參數化查詢更簡單,特別是jdbc,不少人會偷懶使用不安全的方式。
5、JOOQ的失敗之處
可能大部分人會不一樣意,雖然Hibernate、JPA仍然大行其道,是最主流的持久化框架,但其實這種封裝SQL的純正ORM已通過時,效益低於使用它們的代價,應該淘汰了。MyBatis雖然有不少優勢,但它的優勢JOOQ基本上都有,並且多數還更好。MyBatis最大的缺點是難以免寫xml文件,xml文件編寫困難,容易出錯,還不容易查找錯誤。相對於JOOQ,MyBatis在多數狀況下沒有任何優點。
Ebean同時具備不少不一樣框架的優勢,但它是基於JPA的,不免有JPA的各類限制,這是致命的缺點。
JOOQ這個極端輕量級的框架技術上是最完美的,忽然有一天幾個Web系統同時崩了,最後發現是JOOQ試用期過時了,這是JOOQ的失敗之處,它不是徹底免費的,只是對MySql之類的開源數據庫免費。
最終,我決定選擇JDBC Template。