在架構(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.

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)的方法, 然后解析方法上注解的字符串.

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ǔ)句了.


簡(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ǔ)句.

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

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)的方法.


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

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

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

記錄增加.

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

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

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


至此大功告成. 這樣有點(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í)為人處世的能力.