1. 程式人生 > >通用DAO之MyBatis封裝,封裝通用的增刪改查(一)

通用DAO之MyBatis封裝,封裝通用的增刪改查(一)

曾經用過同事的一個基於Hibernate的通用增刪改查框架,當時我的感覺相方便,簡直是開發小型專案的不二選擇,並且那個‘框架’也做為了當時公司裡的標準。

膜拜歸膜拜,勤於鑽研善學善用是鞭長一族的傳統美德!作為鞭長創始人阿海,我認為膜拜的同時更有必要將其技術學為己用。

還好Eclipse中帶有一個反編譯的外掛,可以清楚的看到Jar包中的原始碼,經過一下午的研究,得出結論:

       其實也就那麼回事兒,吧PO類通過反射動態轉換成了HQL語句。

       毫不誇張的說,這東西我閉著眼睛也能做出來^.^~

既然要做,那就做的徹底一些,既然要封裝,那就從底層真正封裝成為一個屬於自己的框架!

遵從阿海的一貫作風,說幹就幹,首先花了半個小時溫習了一下JDBC的知識,又抽時間在網上瀏覽了一些資料庫底層的框架,還看過Mybatis和Hibernate的原始碼,雖然看不太懂,但對他們的基本工作模式也是有了一定的深入的瞭解。

於是就開寫了,同樣是根據資料庫驅動封裝成對應的SQL語句,什麼增刪改查拉,各種花式查詢啦,開幹!

這套資料庫框架也沒有想過什麼霸氣的名字,我且叫他CRUD框架。有的時候我會向朋友們戲稱為《大屌牌兒CRUD框架》

說到這裡,且聽我先介紹一下這套RCUD框架的結構。

       大體也就分為五個部分,因為是初做,沒有什麼快取之類的東西,但是他相對於Hibernate以及同事的那個基於Hibernate來說,有一個很有效率的亮點,就是所謂的動態Sql。

1、動態Sql算是一部分吧,他是基於一個支援鏈式操作的WherePrams類實現Sql的生成。

2、再有就是資料庫訪問層,這裡是和C3P0進行整合,使用的C3P0連線池,並且在其基礎上進行裝飾,讓Spring代理了他的SqlSession連結,方便對事物的控制。

3、然後是一個反射類,這裡他主要是獲取一個實體類的fields,和類名以及實體類中的類註解、欄位註解。並且負責對SqlResult的封裝。

4、便是註解部分類,註解大部分用作標識,例如@TempField表示非入庫欄位(臨時欄位,不計入增刪改查的操作)、@ID、@TabName、@FieldName之類的。則標識實體類資料庫中對應的表名和欄位。若沒有寫該註解的話,CRUD框架則會用類名和欄位名作為表和欄位的查詢(會自動將駝峰標識格式化為下劃線分割)

5、事務處理類,這個是後來加上的,一開始準備用Spring的@Transactional控制事務,但是實際測試不但起不到效果,還會有衝突,具體是如何將事務託管給Spring我還是不太清楚。我看的Mybatis原始碼中頁沒有Spring-mybatis整合包的原始碼,所以無從下手,所以不久我便自己寫了一個事務處理機制,用的是@TranMethod方法,這個方法可以標註到Service方法中,也可以標註到Controller方法中。在Controller方法中則該次請求都算作一個事務,在Service中,則一個方法算是一個事務。我一般飆在Controller方法上。

先從動態SQL,大家可能會首先想到MyBatis,的確,MuBatis的亮點之一就是動態可配的軟編碼Sql。

而我的所說的這個動態SQL屬於硬編碼,但不要聽到硬編碼就不屑一顧,其實開發後期改庫的可能性並不大,也很少有人在後期修改MyBatis的Mapper檔案,至少我是這樣。有的時候雖然避免不了增改欄位,但是這的確屬於極少數,即使遇到這種情況,我認為我會接受重新把專案編譯一下的方案。再者,開發階段我更樂意把精力集中到業務上。還有一個原因就是硬編碼的開發成本實在是太低了,所以我選擇了硬編碼。

之所以這麼重點的強調動態SQL,是因為他實在是太他媽的完美了,他支援鏈式操作,一個簡單的查詢完全可以寫成Method.createDefault();

通常的查詢吧,也是相當方便:

List list = list(POJO.class,

Method.where(xxx,C.xx, xxxx)

.and(xxx, xx, xx)

.or(xxx, xxx, xx)

.in(listField(POPO.class, fieldname, Method.where(xxx, xxx, xxx)))

);

吹了這麼多,相信一些用心的朋友可能看出這個框架的中心結構了,中心結構就是一個Where類,這個Where是一個可以鏈式操作的類,類似於StringBuffer的append()方法。

同時,也通過遞迴的方式支援了巢狀操作。

他可以將複雜的函式格式化為一條完整的高階Sql,不需要多次查詢,這點兒靈活性和易用性,是朋友那個Hibernate框架不能比擬的。

舉個簡單巢狀查詢名為Po的這個類的例子:

       CRUD框架:

       List list = list(Po.class, Method.createDefault().in( aid,

 listField(Apo.class, id, Method.where( sex, C.Eq , 1));

));

同事基於Hibernate的封裝:

String[] filed = {id};

//第一次查詢(Integer.MAXVALUE是用來分頁的,前者要分頁的話,可以直鏈式追加limit()方法)

List idLIst =  listPropinoty(Apo.class, Factory.create(sex, C.eq , 1),0, Integer.MAXVALUE , filed);

String[] ids = idLIst.toArray(String.class, idLIst.size());

//第二次查詢

List list = list(Po.class , 0, Integer.MAXVALUE , Factory.create( aid, ids));

不難看出,前者一次查詢就夠了,後者則需要兩次查詢。

如果對比不明顯的話那麼,再舉一個簡單的例子:

CRUD 框架(一條Sql搞定,採用連結串列+別名的方式實現)

List list = List(Po.class, Method.createDefault()

.framTo(img, ImgResource.class, id, url));

基於Hibernate的封裝:

       List list = list(Po.class, 0, Integer.MAXVALUE);

       for(Po po : list){

//看,又開始查詢了,而且是迴圈查詢,例如上面list中有100個Po的話,就要    迴圈查詢100次,假如一千條甚至一萬條呢?

              ImgResource img = list(ImgResource.class, 0, Integer.MAXVALUE,

Factory.create(id, C.eq, po.getImg()));

              if(null != img){

                     po.setImg(img.getUrl());

}

}

不多吹了,吹了這麼多到頭來,《大屌牌兒CRUD框架》仍然是一個失敗品。為誰麼這麼說呢,我雖然對他進行了了簡單的測試,然而並沒有把他應用到專案中。一直到阿海開發一套擁有IM服務的《鞭長網路使用者管理平臺》時,才加以使用,開發很順暢,然而部署到伺服器中了以後,才發現《大屌牌兒CRUD框架》有致命的BUG,為什麼說致命呢?因為執行兩天後,他就掛了!

掛了就重啟,重啟了就又掛。。。反反覆覆,阿海也試著再找原因,但是一直沒有找到。

看來還是技術不夠成熟,所以,暫時先放下自己開發框架的這個幼稚的想法,轉攻Mybatis!準備把Mybatis封裝的像《大屌牌兒CRUD框架》一樣神奇。

當然,Mybatis我是封裝成功了的,不然我也不會寫這篇文章了,本來想出一篇文章概括完,結果寫起來才發現,要寫的東西實在是太多了,所以阿海儘量精簡,然而前言剛介紹完畢,就發現已經碼了很多字了,或許是有敲程式碼的功底,才讓我堅持敲到這裡的。

哦了,回頭繼續釋出《通用DAO之MyBatis封裝,封裝通用的增刪改查(二)。》