mybatis與springdata的一些簡單比較與思考


主題

  最近在用mybatis做項目,有一些感觸想記錄下,主要是mybatis(以及它的一些插件)相比較於Spring data(或者jpa,hibernate等)的優勢地方.

 

感觸

我覺得mybatis相比於Spring data的最大的幾個優勢的地方在於:

 

動態查詢

不管是在之前的公司還是現在的公司都有很多這樣的業務..比如進來先是一個查詢界面,有N多條件,然后下面是個根據條件分頁查詢的數據,查出數據以后你可以進行一些修改呀查看呀等等操作.

這樣的業務如果是Spring data來做的話比較麻煩.

因為上面的條件用戶是可以輸入也可以不輸入的.在原本的公司我看到有幾種解決方法:

1.自己動態的拼接hql.所以service的代碼里會出現很多if(StringUtils.isEmpty(xxxx查詢條件)){hql += "and xxx條件 = :XXX參數"}類似於這樣的代碼.這樣首先是hql拼接,可讀性是比較差的,另外SQL是在service層拼接的.可能代碼復用的概率會小一點.

2.公司有自己的封裝(http://www.cnblogs.com/abcwt112/p/5874401.html).簡單來說就是指定一下這個查詢是對應哪個entity.然后根據傳過來的request里的paramter找到entity對應的field然后還是拼接sql....只不過自己在service里不用拼接了...可以稍微簡化一些代碼...但是不是很靈活..有些功能還沒封裝.比如or的條件連接就不行.只能拼接and...然后不能嵌套查詢..所以可以說是1方法的簡化版但是相比於自己拼接SQL有些常用的功能做不到.

3.雖然公司我一直沒看到有人用過.但是我知道.Spring data是在jpa外包裝了一層,jpa是有criteria的查詢方式的.spring data也有相應的Specifications的那種查詢方式.這種方法可以幫助我們動態拼接查詢條件..(這種查詢方式我用的很少.可能說的不一定對).我覺得這種查詢方式有個最不方便的地方在於如果要多表關聯查詢,你的entity里沒有@onetomany或者@manytomany或者@onetoone這樣的關鍵的話你是取不到另外關聯的那張表的..這樣的話你就不可能拼接那個where條件..這樣的情況還是蠻常見的,因為表的關聯太多了.不是所有的關聯都寫成了成員域..所以這種查詢方法也是有缺陷的..

總結下的話就是Spring data動態查詢拼接SQL比較麻煩..主要是在service里經常要判斷XXX參數用戶有沒有輸入..有輸入就hql+=....看起來SQL不直觀.都不知道完整的SQL結構,也很容易拼錯.

 

這樣的業務如果mybatis來做:

1.按照我現在公司的套路,大概是最簡單粗暴的.我們mybatis沒用任何插件,也沒有自動生成任何XML.純手寫.

那么我要做的也就是在XML里寫個查詢SQL對應的select語句.然后再拼接條件的時候可以用<if>標簽去過濾就行了.

這樣的好處就是SQL比較直觀,到底查什么表一目了然,然后因為拼接SQL相當於是在dao層,所以復用概率會大一些.比如其他業務也要查這張表的數據,可以復用.

 

Entity與DTO

這個問題主要是entity與dto之間數據拷貝的問題,還有一些建表問題,沒用過hibernate或者用hibernate自動生成表的朋友可能不會有這樣的感覺.

Spring data:

因為spring data數據庫映射到實體用的是entity,而前台顯示用的是dto.所以數據肯定需要拷貝. 另外一個比較坑爹的地方是entity如果和spring data的session關聯了的話,如果修改了字段,即使不顯示的調用dao.update,在出了事務以后也會自動更新數據庫的(因為是受管實體).所以拷貝是必須的.這樣的話會需要一些時間,另外對象拷貝也蠻麻煩的.特別是還有集合的情況更是麻煩.(之前公司用cglib的bean copier http://www.cnblogs.com/abcwt112/p/6073103.html)

還有個小坑就是如果查出來的對象有懶加載的集合屬性,那么當然前后台交互的時候,比如用jackson將entity轉化成json的時候會自動調用entity的get方法,導致懶加載被觸發,然后hibernate自動調用SQL去查詢數據,然而那個時候事務早已關閉,會報錯,這也是一個坑,以前公司基本上是一個業務域的相關聯對象一次性查出來(也不是很多數據).

另外當建表不是很規范的時候(比如多表關聯沒有使用外鍵關聯,而是共享主鍵,又是單向關聯的時候)spring data jpa的級聯操作可能會產生問題.(http://www.cnblogs.com/abcwt112/p/4849416.html)

 

mybatis:

很簡單..查出什么數據直接用....

公司仍然有entity和dto.其實我覺得只需要留下dto就足夠了.有2套對象的話如果dao里的方法的參數不同也是需要轉化的.mybatis只是把數據庫查詢的結果映射到了dto上.我覺得沒那么復雜...不需要2套對象.只有一套dto就足夠了..還簡單些.

 

非主鍵的CRUD操作

表的主鍵在很多時候都是ID自增或者uuid,但是用戶並不會知道,他們知道的可能是業務上面的主鍵,比如超市商品的條形碼等等.這種時候我們操作數據庫可能不是根據id而是根據這種業務上面的唯一標示去操作數據庫.

spring data:

我一直覺得這是Spring data相比於hibernate和jpa最引以為傲的功能,可以根據dao的方法名自動映射成sql.

比如findByName會被自動翻譯成select * from xxx where name = :name

updateNameByStateAndLevelIsNotNull會被自動翻譯成update xxx set name = :name where state = :state and level is not null

可以說Spring data可以在絕大部分情況下避免寫SQL.所以操作數據庫比較方便.美中不足的就是如果SQL比較長參數比較多..那么方法名也會比較長....有時候看起來比較累.

 

mybatis:

讓我從首選spring data變成首選mybatis作為持久層框架的一個原因就在這里.(雖然spring data已經做的很好了)

按照公司的做法我們需要手寫SQL...那是很坑爹的.絕對沒有Spring data好用.但是eclipse有個mybatis的generator插件.......

他可以自動幫我們生成XML..這里生成的幾個方法非常非常有用....

1     List<TmTransportAddressDto> selectByExample(TmTransportAddressExample example);
2 
3     int updateByExampleSelective(@Param("record") TmTransportAddressDto record, @Param("example") TmTransportAddressExample example);
4 
5     int updateByExample(@Param("record") TmTransportAddressDto record, @Param("example") TmTransportAddressExample example);
6 
7     int countByExample(TmTransportAddressExample example);
8 
9     int deleteByExample(TmTransportAddressExample example);
View Code

就是這幾個example方法.

看一個使用example的小例子:

1             TmTransportAddressDto tmTransportAddressDto = new TmTransportAddressDto();
2             tmTransportAddressDto.setExecutePerson(tmTransportChangeRecord.getDriverNameAfter());
3             tmTransportAddressDto.setExecuteDeviceNo(tmTransportChangeRecord.getPlateNumberAfter());
4             tmTransportAddressDto.setExecuteTelephone(tmTransportChangeRecord.getDriverPhoneAfter());
5             TmTransportAddressExample tmTransportAddressExample = new TmTransportAddressExample();
6             tmTransportAddressExample.createCriteria()
7                     .andExecuteTelephoneEqualTo(tmTransportChangeRecord.getDriverPhoneBefore()).andSnEqualTo(sn);
8             countUpdate += tmTransportAddressDao.updateByExampleSelective(tmTransportAddressDto,
9                     tmTransportAddressExample);

上面這9行代碼相當於是更新tmTransportAddress表的executePerson,executeDeviceNo等4個字段 where 條件是executeTelphone = XXX and sn = xxx.

這種用法比Spring data還要簡單,連dao的方法名都不用寫了(其實還是要寫的.只是寫在了example里...generator自動生成了通用的XML SQL片段)...非常非常好用!

再很多情況下只要自動生成了xml文件以后基本SQL和額外的dao方法都不需要寫了..因為example相當於是動態拼接SQL的方法.可以拼接出任意的SQL.

不過我覺得這種用法還是不太適合頁面上那種動態條件分頁查詢,因為也需要在service里拼接條件..只是簡化了一些.並沒有自己在XML里寫完整的SQL直觀.

 

小結

以上便是我最近2個月學習mybatis的一些感觸.mybatis在很多情況下確實是比spring data簡單好用(其實就是拼SQL的功能很強大).

后面會再分享一些如果我是架構師會怎么在項目里使用mybatis的一些想法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM