項(xiàng)目架構(gòu)升級(jí)史-架構(gòu)2.1

在架構(gòu)3.0中,已經(jīng)說(shuō)明了2.0的關(guān)于數(shù)據(jù)庫(kù)字段修改的問(wèn)題.
3.0是直接使用nosql解決這個(gè)問(wèn)題, 那能不能即使用mysql和mybatis也能解決數(shù)據(jù)庫(kù)字段修改的問(wèn)題.
那么現(xiàn)在的問(wèn)題就是: 修改了數(shù)據(jù)庫(kù)字段,mybatis的sql能自動(dòng)變成相應(yīng)的sql.

為了解決這個(gè)問(wèn)題, 自然而然就想到了動(dòng)態(tài)修改 Mapper上注解中的sql語(yǔ)句. 想到曾經(jīng)看到過(guò)mybatis plus好像也是繼承BaseMapper,并不需要寫(xiě)Select 等注解, 就已經(jīng)有了增刪改查的能力.

通過(guò)研究mybatis和mybatis plus的源碼, 再結(jié)合<<深入淺出MyBatis技術(shù)原理與實(shí)戰(zhàn)>>這本書(shū)很快就明白了mybatis和plus的原理.

我現(xiàn)在要做的是, 類(lèi)似 mybatis plus 繼承BaseMapper 所有mapper都有增刪改查的能力,并且數(shù)據(jù)庫(kù)字段的修改不需要修改mapper.
那為什么不直接使用plus呢?
1 plus的核心也是修改mybatis的源碼, 再整合自己的代碼,很多功能我并不需要 .
2 我的核心還是使用mybatis只不過(guò)需要mapper自帶這些基礎(chǔ)增刪改查.

那么就需要完成以下兩個(gè)功能
1 提供動(dòng)態(tài)增刪改查sql
這個(gè)好說(shuō),以前sql的自動(dòng)生成是從word文檔讀取生成的,那么如果想獲取準(zhǔn)確的sql只需要從數(shù)據(jù)庫(kù)中獲取每一個(gè)表的字段,通過(guò)拼接即可生成準(zhǔn)確的sql, 寫(xiě)一個(gè)工具類(lèi)即可.

這個(gè)Sql類(lèi)保存一個(gè)map包含所有表的sql語(yǔ)句.
比如key是"UserMapper.getInfo" value是"select * from user".
Sql.printSql("表名") 即可打印存儲(chǔ)的sql.


image.png

2 動(dòng)態(tài)替換sql
那么就需要知道m(xù)ybatis是怎么加載mapper以及怎么使用Select注解上的sql的.

mybatis是通過(guò)MapperAnnotationBuilder這個(gè)類(lèi)加載基于注解的mapper.
其中type就是自定義mapper的class類(lèi), 例如UserMapper的class .(java中是UserMapper.class, kotlIn中是UserMapper::class.java)
這里的意思是遍歷這個(gè)class類(lèi)的方法, 然后解析方法上注解的字符串.


image.png

LanguageDriver也可以動(dòng)態(tài)替換sql, mybatis官方文檔有詳細(xì)講解.一開(kāi)始使用這個(gè)但是不能動(dòng)態(tài)獲取mapper的類(lèi)名.
SqlSource就是保存具體sql語(yǔ)句的地方,sql就是實(shí)際的sql語(yǔ)句了.

image.png
image.png

簡(jiǎn)單來(lái)說(shuō), 就是 mybatis 找到所有包下面的帶有@Mapper注解的接口, 然后遍歷它的方法, 取出方法上注解的sql存起來(lái).
如果想動(dòng)態(tài)替換sql 只需要修改buildSqlSourceFromStrings方法, 根據(jù)sql的值替換成實(shí)際的sql即可.

2.1 改寫(xiě)baseMapper
我們改寫(xiě)buildSqlSourceFromStrings方法, 如果發(fā)現(xiàn)是BaseModel 開(kāi)頭的sql語(yǔ)句, 那么就需要替換成實(shí)際sql語(yǔ)句.

但是怎么知道要替換成哪一個(gè)表的sql呢, 所以有個(gè)規(guī)定 UserMapper 對(duì)應(yīng)的是user表,根據(jù)mapper的類(lèi)名替換.

在buildSqlSourceFromStrings方法里取到該mapper的類(lèi)名, 以BaseModel.getInfo為列,先把BaseModel.getInfo替換成 UserMapper.getInfo, 因?yàn)樵赟ql類(lèi)已經(jīng)存了UserMapper.getInfo的sql語(yǔ)句.再把UserMapper.getInfo替換成實(shí)際的sql語(yǔ)句.


image.png

2.2 怎么修改mybatis源碼
很簡(jiǎn)單,在項(xiàng)目源碼文件夾建立一個(gè)包名類(lèi)名相同的類(lèi), 虛擬機(jī)在加載java類(lèi)的時(shí)候會(huì)優(yōu)先加載src下面的類(lèi).

以下就是修改的三個(gè)地方


image.png

removeMethod方法是為了, 如果重載了getInfo 方法, mybatis就會(huì)報(bào)錯(cuò), 因?yàn)楦割?lèi)和子類(lèi)都有g(shù)etInfo方法, 并且這兩個(gè)getInfo上的注解都有sql, 就不知道用哪一個(gè)了. removeMethod就是如果子類(lèi)重載了方法, 就去除掉父類(lèi)的方法.

image.png
image.png

實(shí)際效果
VisibilityMapper直接繼承BaseMapper 沒(méi)有sql語(yǔ)句.


image.png

默認(rèn)有一行記錄.


image.png

執(zhí)行測(cè)試用例.
image.png

記錄增加.
image.png

新增一個(gè)字段 test 并賦值.


image.png

現(xiàn)在只需在代碼中的model增加一個(gè)字段test.


image.png

再次執(zhí)行測(cè)試用例, 輸出中自動(dòng)帶上了test, 插入的時(shí)候也帶上了test.


image.png

image.png

至此大功告成. 這樣有點(diǎn)像mybatis和hibernate的結(jié)合體, 既有hibernate面向?qū)ο蟛僮鲾?shù)據(jù)庫(kù)的功能又保留了
mybatis操作sql的靈活性.

完成這個(gè)功能有兩大難點(diǎn)
1 源碼的理解
因?yàn)榈诙夜臼侨A為外包, 所以接觸到了華為的項(xiàng)目,那是一個(gè)歷史悠久的大項(xiàng)目, 源碼多的嚇?biāo)廊? 為了搞清原理,研究過(guò)項(xiàng)目源碼,所以mybatis的源碼量相對(duì)華為的還是很小的,也遠(yuǎn)沒(méi)有華為的復(fù)雜.所以看mybatis和plus的源碼過(guò)程是比較簡(jiǎn)單的.

2 修改源碼
這也是因?yàn)槿A為的項(xiàng)目,當(dāng)時(shí)有個(gè)需求需要把他們的web端部署到websphere上,但是它使用的axis2框架一直有問(wèn)題,所以那時(shí)天天研究websphere的類(lèi)加載機(jī)制.還有就是華為的web框架沒(méi)有源碼, 但是我要調(diào)試需要知道里面到底是怎么執(zhí)行的,所以把需要調(diào)試的類(lèi)放到自己src路徑下增加調(diào)試語(yǔ)句,就可以清楚的知道這個(gè)類(lèi)是干什么的.

所以有時(shí)候看到網(wǎng)上說(shuō)外包這不好那不好,但是我在外包的這一段經(jīng)歷,給了我很大的成長(zhǎng),也是在那里知道了我認(rèn)為作為程序員最重要的思想-自動(dòng)化.也因此把自動(dòng)化思想全應(yīng)用在了現(xiàn)在的公司.

任何公司都有它的優(yōu)點(diǎn)和缺點(diǎn),作為一個(gè)員工,我們踏踏實(shí)實(shí)做好自己的事,閑暇的時(shí)候多學(xué)習(xí),開(kāi)闊自己的眼界,不僅是學(xué)習(xí)技術(shù),還要多學(xué)習(xí)為人處世的能力.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容