<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          MyBatis、Hibernate、Spring Data JPA哪個最好用?

          共 5297字,需瀏覽 11分鐘

           ·

          2021-05-11 21:24

            Java大聯(lián)盟

            幫助萬千Java學習者持續(xù)成長

          關(guān)注



          segmentfault.com/a/1190000018472572


          B 站搜索:楠哥教你學Java

          獲取更多優(yōu)質(zhì)視頻教程


          因為項目需要選擇數(shù)據(jù)持久化框架,看了一下主要幾個流行的和不流行的框架,對于復雜業(yè)務(wù)系統(tǒng),最終的結(jié)論是,JOOQ是總體上最好的,可惜不是完全免費,最終選擇JDBC Template。
          Hibernate和Mybatis是使用最多的兩個主流框架,而JOOQ、Ebean等小眾框架則知道的人不多,但也有很多獨特的優(yōu)點;
          而JPA則是一組Java持久層Api的規(guī)范,Spring Data JPA是JPA Repository的實現(xiàn),本來和Hibernate、Mybatis、JOOQ之類的框架不在同一個層次上,但引入Spring Data JPA之類框架之后,我們會直接使用JPA的API查詢更新數(shù)據(jù)庫,就像我們使用Mybatis一樣,所以這里也把JPA和其他框架放在一起進行比較。
          同樣,JDBC和其他框架也在同一層次,位于所有持久框架的底層,但我們有時候也會直接在項目中使用JDBC,而Spring JDBC Template部分消除了使用JDBC的繁瑣細節(jié),降低了使用成本,使得我們更加愿意在項目中直接使用JDBC。

          1、SQL封裝和性能
          在使用Hibernate的時候,我們查詢的是POJO實體類,而不再是數(shù)據(jù)庫的表,例如hql語句 select count(*) from User,里面的User是一個Java類,而不是數(shù)據(jù)庫表User。
          這符合ORM最初的理想,ORM認為Java程序員使用OO的思維方式,和關(guān)系數(shù)據(jù)庫的思維方式差距巨大,為了填補對象和關(guān)系思維方式的鴻溝,必須做一個對象到關(guān)系的映射。
          在Java的對象世界中,程序員可以使用純的對象的思維方式,查詢POJO對象,查詢條件是對象屬性,不再需要有任何表、字段等關(guān)系的概念,這樣java程序員就更容易做持久層的操作。
          JPA可以視為Hibernate的兒子,也繼承了這個思路,把SQL徹底封裝起來,讓Java程序員看不到關(guān)系的概念,用純的面向?qū)ο笏枷?,重新?chuàng)造一個新的查詢語言代替sql,比如hql,還有JPQL等。支持JPA的框架,例如Ebean都屬于這種類型的框架。
          但封裝SQL,使用另一種純的面向?qū)ο蟛樵冋Z言代替sql,真的能夠讓程序員更容易實現(xiàn)持久層操作嗎?MyBatis的流行證明了事實并非如此,至少在大多數(shù)情況下,使用hql并不比使用sql簡單。
          首先,從很多角度上看,hql/JPQL等語言更加復雜和難以理解;其次就是性能上明顯降低,速度更慢,內(nèi)存占用巨大,而且還不好優(yōu)化。最為惱火的是,當關(guān)系的概念被替換為對象的概念之后,查詢語言的靈活性變得很差,表達能力也比sql弱很多。寫查詢語句的時候受到各種各樣的限制,一個典型的例子就是多表關(guān)聯(lián)查詢。
          不管是hibernate還是jpa,表之間的連接查詢,被映射為實體類之間的關(guān)聯(lián)關(guān)系,這樣,如果兩個實體類之間沒有(實現(xiàn))關(guān)聯(lián)關(guān)系,你就不能把兩個實體(或者表)join起來查詢。
          這是很惱火的事情,因為我們很多時候并不需要顯式定義兩個實體類之間的關(guān)聯(lián)關(guān)系就可以實現(xiàn)業(yè)務(wù)邏輯,如果使用hql,只是為了join我們就必須在兩個實體類之間添加代碼,而且還不能逆向工程,如果表里面沒有定義外鍵約束的話,逆向工程會把我們添加的關(guān)聯(lián)代碼抹掉。
          MyBatis則是另外一種類型的持久化框架,它沒有封裝SQL也沒有創(chuàng)建一種新的面相對象的查詢語言,而是直接使用SQL作為查詢語言,只是把結(jié)果填入POJO對象而已。
          使用sql并不比hql和JPQL困難,查詢速度快,可以靈活使用任意復雜的查詢只要數(shù)據(jù)庫支持。從SQL封裝角度上看,MyBatis比Hibernate和JPA成功,SQL本不該被封裝和隱藏,讓Java程序員使用SQL既不麻煩也更容易學習和上手,這應(yīng)該是MyBatis流行起來的重要原因。
          輕量級持久層框架JOOQ也和MyBatis一樣,直接使用SQL作為查詢語言,比起MyBatis,JOOQ雖然知名度要低得多,但JOOQ不但和MyBatis一樣可以利用SQL的靈活性和高效率,通過逆向工程,JOOQ還可以用Java代碼來編寫SQL語句,利用IDE的代碼自動補全功能,自動提示表名和字段名,減少程序員記憶負擔,還可以在元數(shù)據(jù)發(fā)生變化時發(fā)生編譯錯誤,提示程序員修改相應(yīng)的SQL語句。
          Ebean作為一種基于JPA的框架,它也使用JPQL語言進行查詢,多數(shù)情況下會讓人很惱火。但據(jù)說Ebean不排斥SQL,可以直接用SQL查詢,也可以用類似JOOQ的DSL方式在代碼中構(gòu)造SQL語句(還是JPQL語句?),但沒用過Ebean,所以具體細節(jié)不清楚。
          JDBC Template就不用說了,它根本沒做ORM,當然是純SQL查詢。利用Spring框架,可以把JDBC Template和JPA結(jié)合起來使用,在JPA不好查詢的地方,或者效率低不好優(yōu)化的地方使用JDBC,緩解了Hibernate/JPA封裝SQL造成的麻煩,但我仍沒看到任何封裝SQL的必要性,除了給程序員帶來一大堆麻煩和學習負擔之外,沒有太明顯的好處。

          2、DSL和變化適應(yīng)性
          為了實現(xiàn)復雜的業(yè)務(wù)邏輯,不論是用SQL還是hql或者JPQL,我們都不得不寫很多簡單的或者復雜的查詢語句,ORM無法減少這部分工作,最多是用另一種面向?qū)ο箫L格的語言去表達查詢需求,如前所述,用面向?qū)ο箫L格的語言不見得比SQL更容易。
          通常業(yè)務(wù)系統(tǒng)中會有很多表,每個表都有很多字段,即便是編寫最簡單的查詢語句也不是一件容易的事情,需要記住數(shù)據(jù)庫中有哪些表,有哪些字段,記住有哪些函數(shù)等。寫查詢語句很多時候成為一件頭疼的事情。
          QueryDSL、JOOQ、Ebean甚至MyBatis和JPA都設(shè)計一些特性,幫助開發(fā)人員編寫查詢語句,有人稱之為“DSL風格數(shù)據(jù)庫編程”。最早實現(xiàn)這類功能的可能是QueryDSL,把數(shù)據(jù)庫的表結(jié)構(gòu)逆向工程為java的類,然后可以讓 Java 程序員能夠用java的語法構(gòu)造出一個復雜的查詢語句,利用IDE的代碼自動補全功能,可以自動提示表名、字段名、查詢語句的關(guān)鍵字等,很成功的簡化了查詢語句的編寫,免除了程序員記憶各種名字、函數(shù)和關(guān)鍵字的負擔。
          QueryDSL有很多版本,但用得多的是QueryDSL JPA,可以幫助開發(fā)人員編寫JPQL語句,如前所述,JPQL語句有很多局限不如SQL靈活高效。后來的JOOQ和Ebean,基本上繼承了QueryDSL的思路,Ebean基本上還是JPA風格的ORM框架,雖然也支持SQL,但不清楚其DSL特性是否支持SQL語句編寫,在官網(wǎng)上看到的例子都是用于構(gòu)造JPQL語句。
          這里面最成功的應(yīng)該是JOOQ,和QueryDSL不同,JOOQ的DSL編程是幫助開發(fā)人員編寫SQL語句,拋棄累贅的ORM概念,JOOQ這個功能非常輕小,非常容易學習和使用,同時性能也非常好,不像QueryDSL和Ebean,需要了解復雜的JPA概念和各種奇異的限制,JOOQ編寫的就是普通的SQL語句,只是把查詢結(jié)果填充到實體類中(嚴格說JOOQ沒有實體類,只是自動生成的Record對象),JOOQ甚至不一定要把結(jié)果轉(zhuǎn)換為實體類,可以讓開發(fā)人員按照字段取得結(jié)果的值,相對于JDBC,JOOQ會把結(jié)果值轉(zhuǎn)換為合適的Java類型,用起來比JDBC更簡單。
          傳統(tǒng)主流的框架對DSL風格支持得很少,Hibernate里面基本上沒有看到有這方面的特性。MyBatis提供了"SQL語句構(gòu)建器"來幫助開發(fā)人員構(gòu)造SQL語句,但和QueryDSL/JOOQ/Ebean差很多,不能提示表名和字段名,語法也顯得累贅不像SQL。
          JPA給人的印象是復雜難懂,它的MetaModel Api繼承了特點,MetaModel API+Criteria API,再配合Hibernate JPA 2 Metamodel Generator,讓人有點QueryDSL JPA的感覺,只是繞了一個大大的彎,疊加了好幾層技術(shù),最后勉強實現(xiàn)了QueryDSL JPA的簡單易懂的功能。
          很多人不推薦JPA+QueryDSL的用法,而是推薦JPA MetaModel API+Criteria API+Hibernate JPA 2 Metamodel Generator的用法,讓人很難理解,也許是因為這個方案是純的標準的JPA方案。
          數(shù)據(jù)庫DSL編程的另一個主要賣點是變化適應(yīng)性強,數(shù)據(jù)庫表結(jié)構(gòu)在開發(fā)過程中通常會頻繁發(fā)生變化,傳統(tǒng)的非DSL編程,字段名只是一個字符串,如果字段名或者類型改變之后,查詢語句沒有相應(yīng)修改,編譯不會出錯,也容易被開發(fā)人員忽略,是bug的一個主要來源。
          DSL編程里面,字段被逆向工程為一個java類的屬性,數(shù)據(jù)庫結(jié)構(gòu)改變之后,作為java代碼一部分的查詢語句會發(fā)生編譯錯誤,提示開發(fā)人員進行修改,可以減少大量bug,減輕測試的負擔,提高軟件的可靠性和質(zhì)量。

          3、跨數(shù)據(jù)庫移植
          Hibernate和JPA使用hql和JPQL這類數(shù)據(jù)庫無關(guān)的中間語言描述查詢,可以在不同數(shù)據(jù)庫中無縫移植,移植到一個SQL有巨大差別的數(shù)據(jù)庫通常不需要修改代碼或者只需要修改很少的代碼。Ebean如果不使用原生SQL,而是使用JPA的方式開發(fā),也能在不同數(shù)據(jù)庫中平滑的移植。
          MyBatis和JOOQ直接使用SQL,跨數(shù)據(jù)庫移植時都難免要修改SQL語句。這方面MyBatis比較差,只有一個動態(tài)SQL提供的特性,對于不同的數(shù)據(jù)庫編寫不同的sql語句。
          JOOQ雖然無法像Hibernate和JPA那樣無縫移植,但比MyBatis好很多。JOOQ的DSL很大一部分是通用的,例如分頁查詢中,Mysql的limit/offset關(guān)鍵字是很方便的描述方式,但Oracle和SQLServer的SQL不支持,如果我們用JOOQ的DSL的limit和offset方法構(gòu)造SQL語句,不修改移植到不支持limit/offset的Oracle和SQLServer上,我們會發(fā)現(xiàn)這些語句還能正常使用,因為JOOQ會把limit/offset轉(zhuǎn)換成等價的目標數(shù)據(jù)庫的SQL語句。
          JOOQ根據(jù)目標數(shù)據(jù)庫轉(zhuǎn)換SQL語句的特性,使得在不同數(shù)據(jù)庫之間移植的時候,只需要修改很少的代碼,明顯優(yōu)于MyBatis。
          JDBC Template應(yīng)該最差,只能盡量使用標準sql語句來減少移植工作量。
           
          4、安全性
          一般來說,拼接查詢語句都會有安全隱患,容易被sql注入攻擊。不論是jdbc,還是hql/JPQL,只要使用拼接的查詢語句都是不安全的。對于JDBC來說,使用參數(shù)化的sql語句代替拼接,可以解決問題。而JPA則應(yīng)該使用Criteria API解決這個問題。
          對于JOOQ之類的DSL風格框架,最終會被render為參數(shù)化的sql,天生免疫sql注入攻擊。Ebean也支持DSL方式編程,也同樣免疫sql注入攻擊。
          這是因為DSL風格編程參數(shù)化查詢比拼接字符串查詢更簡單,沒人會拼接字符串。而jdbc/hql/JPQL拼接字符串有時候比參數(shù)化查詢更簡單,特別是jdbc,很多人會偷懶使用不安全的方式。

          5、JOOQ的失敗之處
          可能大部分人會不同意,雖然Hibernate、JPA仍然大行其道,是最主流的持久化框架,但其實這種封裝SQL的純正ORM已經(jīng)過時,效益低于使用它們的代價,應(yīng)該淘汰了。
          MyBatis雖然有很多優(yōu)點,但它的優(yōu)點JOOQ基本上都有,而且多數(shù)還更好。MyBatis最大的缺點是難以避免寫xml文件,xml文件編寫困難,容易出錯,還不容易查找錯誤。相對于JOOQ,MyBatis在多數(shù)情況下沒有任何優(yōu)勢。
          Ebean同時具有很多不同框架的優(yōu)點,但它是基于JPA的,難免有JPA的各種限制,這是致命的缺點。
          JOOQ這個極端輕量級的框架技術(shù)上是最完美的,突然有一天幾個Web系統(tǒng)同時崩了,最后發(fā)現(xiàn)是JOOQ試用期過期了,這是JOOQ的失敗之處,它不是完全免費的,只是對MySql之類的開源數(shù)據(jù)庫免費。


          推薦閱讀

          1、Spring Boot+Vue項目實戰(zhàn)

          2、B站:4小時上手MyBatis Plus

          3、一文搞懂前后端分離

          4、快速上手Spring Boot+Vue前后端分離


          楠哥簡介

          資深 Java 工程師,微信號 southwindss

          《Java零基礎(chǔ)實戰(zhàn)》一書作者

          騰訊課程官方 Java 面試官,今日頭條認證大V

          GitChat認證作者,B站認證UP主(楠哥教你學Java)

          致力于幫助萬千 Java 學習者持續(xù)成長。




          有收獲,就在看 
          瀏覽 49
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产亚洲精品美女 | 欧美美女美穴 | 乱老熟女一区二区三区 | 琪琪五月色 | 国产精品毛片久久 |