什么是Mybatis
CRUD框架,面向數(shù)據(jù)庫開發(fā)的腳手架。它提供了支持CRUD操作,還具有以下特性。
Mybatis這套框架的核心在于遵循到位了開閉原則,里氏替換原。組件思想,抓核心思想等。
Mybatis分為三大組件:SQL組裝層,數(shù)據(jù)處理轉(zhuǎn)換層,插件管理層。
Mybatis的核心對象有:BoundSQL,Configuration,SqlSession,MapperProxy,StatementHandler.
一張圖描述下查詢List的幾個步驟

查詢在mybatis大概執(zhí)行過程,"↓"表示下一個執(zhí)行片段。
SqlSessionFactory
↓ 創(chuàng)建SqlSesssion,SqlSession相當于Mybatis的執(zhí)行引擎 預裝載datasource,進入configuration,
注意Datasource如果是在依賴注入容器里,也是Singletone模式的
Configuration
根據(jù)ID在configuration里面找到相應(yīng)的命名空間維度的配置項,Mybatis設(shè)計上基本都是一次初始永久使用的,交給mapperProxy代理類去處理,MapperProxy處理類由它的工廠類MapperProxyFactory創(chuàng)建
↓
MapperProxy 執(zhí)行invoke,這里面有個cache機制
↓
找到MapperMethod觸發(fā)execute,里面有根據(jù)SQLCommandType去路由到不同的處理方式
↓
SqlSession insert() or update()
↓
Plugin 是否有Plugin機制
↓
RoutingStatementHandler 路由處理
↓
ParameterHandler 執(zhí)行參數(shù)處理,
↓
ResultHandler 結(jié)果集處理,游標處理。映射成返回對象
↓
DebuggingPrintLog 有開啟Debug日志才會代理Stmt 或者Psmt或者 Result代理
↓
TransactionHandler 關(guān)閉事物,如果有Spring食物切面就會托管給它去做這個事情
↓
Spring事物代理切面處理器
*可拓展
*調(diào)用鏈短
*支持內(nèi)存分頁
*手動SQL,滿足對SQL性能有要求場景
SQL支持面向語言用注解方式進行組裝,或者用ONGL的方式將SQL邏輯表現(xiàn)在XML語言文檔中
*Mybatis不像Hibernate是一個真正的持久化框架,HBT更像是弱化了SQL這一基礎(chǔ)技能屬性。MB的SQL始終是具備完整性的。
*該框架提供了別名機制,別名可以外部配置然后在運行階段一次性加載到全局的configuration中
Mybatis代碼非常精簡,上手非常容易。源碼理解程度除了ONGL這塊比較抽象,其他部分都很容易理解,本文也是化煩為簡地方式來講解,適用于初學者和老手。Mybatis是Web開發(fā)里面最簡單的框架,很容易了解到原理。
如何快速理解一套框架,我的建議是把它當做一個工具集,既然是工具,先理解它的構(gòu)造和設(shè)計原理,先通過官網(wǎng)描述了解它實現(xiàn)了什么功能,這些功能分別是什么,然后可以以架構(gòu)師的角度去了解它的作用場景。
當了解了以上這些后,再去庖丁解牛的方式去解開它的內(nèi)部構(gòu)造,一般高級語言實現(xiàn)的一個框架在代碼的結(jié)構(gòu)上都是分包的,接著去了解它每個包的作用域,然后再去抽象出它所用到的設(shè)計模式??紤]一下為什么要用到這個設(shè)計模式,當了解了這些之后,就可以上升到如何用好和拓展這個框架了。
*設(shè)計模式:
包裝器(Wrapper關(guān)鍵字的類群體),JDK動態(tài)代理模式,Cglib代理模式。(MapperInterface類),靜態(tài)工廠模式(SqlSessionFactory,
LoggingFactory,
MapperProxyFactory),建造者模式(包含關(guān)鍵字builder的類),策略模式(隱藏式設(shè)計模式,緩存策略模式,日志輸出策略模式,StatementHandler模式,使用者不需要關(guān)注處理細節(jié),只需要告訴Mybatis你要做什么,只需要體現(xiàn)使用者的行為即可),裝飾器模式,ONGL中用到了組合模式(<if>,<else><choosen>等組合tag),Plugin衍生的使用攔截器場景使用的責任鏈設(shè)計模式等(攔截器就是All-in-List then execute-stepbystep-in-chainGroup)。
模擬通訊服務(wù)上的路由器的網(wǎng)絡(luò)分發(fā)功能實現(xiàn)的策略模式:
通過RoutingStatementHandler類就是一個路由器,然后通過StatementType類型來決定跳轉(zhuǎn)到不同的handler。
*包結(jié)構(gòu)
排名不分先后順序
annonations:注解SQL的,作用于SqlBuilder使用場景
binding: 實現(xiàn)Mapper的綁定,里面有個MapperRegister
builder:構(gòu)造Mapper,解析Configuration的基礎(chǔ)配置等
cache:緩存包,裝飾器模式。比如與依賴注入控制反轉(zhuǎn)框架Spring使用時要以外部注入裝載的方式引入redis等緩存中間件。
cursor:游標,獲取Jdbc游標的迭代位置
datasource:數(shù)據(jù)源[jndi數(shù)據(jù)源,普通數(shù)據(jù)源(BasicDatasource)],基于數(shù)據(jù)庫驅(qū)動包的條件下,才能ping上對應(yīng)的數(shù)據(jù)庫,同時,需要設(shè)置鏈接,鏈接的必要屬性一般都是要用戶名和密碼認證通過才可以。
下面是一個jdbc接口和數(shù)據(jù)庫交互的大致過程~
加載jdbc驅(qū)動包->創(chuàng)建鏈接->開啟會話->開啟事物->創(chuàng)建statement->讀場景游標方式迭代結(jié)果集->關(guān)閉statement->寫場景關(guān)閉事物->_遇到異?;貪L事物
exceptions:異常包,這部分使用到了是factory model。
executor:支持JDBC操作的入口包
plugin:插件包,通?;诓寮C制可以實現(xiàn)分頁,SQL執(zhí)行效率上的性能監(jiān)控。
IO:流處理
session: JDBCSession等
logging:日志組件,開啟debug模式時,針對Statement和result進行了打印日志的代理攔截,不影響原來的流程,該怎么往下執(zhí)行還得繼續(xù)。
transaction:事務(wù)包,mybatis對事物這塊簡單地加工了一下,可以支持強制關(guān)閉操作等行為
parsing:sql語句轉(zhuǎn)換包
scripting:腳本包
type: JDBC type handler
mapping: 映射包。鑒別器,boundSQL,resultMap,這個包里面涵蓋了
sql屬性維度,columnType維度,resultMap等維度與ONGL之間的映射模型。這里面幾乎都是PlainObject,幾乎沒有行為透露和傳播。
reflect:反射機制包,針對數(shù)據(jù)庫字段提取出值,通過反射機制映射到property字段里。
獲取反射類內(nèi)部用了取出一次就緩存的動作的。
核心類
Confiuration:Mybatis的核心配置類,頂層類,xml配置項,由XMLConfigurationBuilder提供解析裝載。它提供你全局獲取ResultMap,獲取MapMethed.
MapperRegister:注冊Mapper類。
SqlSessionFactory:通過build創(chuàng)建sqlSession,需要自定義一個datasouce,
比如集成到Spring框架中時會先定義一個DataSource。
BaseExecutor:執(zhí)行 insert,update,select
,delete操作。Mybatis嚴格按照jdbc的CRUD操作返回的類型進行一一對應(yīng)設(shè)計。
MapperProxy:代理類,用jdk動態(tài)代理機制,創(chuàng)建字節(jié)碼方式。XML可以不需要定義接口,但是定義接口就必須要它所包含的package全路徑需要是正確的路徑。
ResultTypeHandler:Jdbc中的ResultType映射成返回ResultType使用的Java類型。Mybatis定義了自己的JdbcType,為什么它不fixed對應(yīng)的Java類型,這是基于開閉原則,因為用戶拿到的type尤其是char這樣的類型豐富多變。它有個TypeRegister機制,用戶可以定義自己的type作用于rst.
SqlSesession:就是用來處理connection,connection的處理流程是:開啟事物,創(chuàng)建stm或者pstm或者callstm,獲取結(jié)果集返回的游標,關(guān)閉事物(遇到異常拋出來)
CacheProvider:緩存提供者,MB提供了namespace作用域緩存和sqlsession兩種緩存作用域。用裝飾者設(shè)計模式設(shè)計出來了多種不同方式的緩存機制。緩存是個多余的設(shè)計,不滿足業(yè)務(wù)場景,一般業(yè)務(wù)層應(yīng)用開發(fā)都單獨使用緩存中間件。比如Spring+redis實現(xiàn)。如果業(yè)務(wù)上的數(shù)據(jù)只需要隔離數(shù)據(jù)庫,可以實現(xiàn)它的cache接口,用redisCache,用靜態(tài)方法獲取靜態(tài)注入的RedisSessionFacotory來使用。
,,,
doPut ();
clear();
update();
,,,

ResultMap:核心類,它的上層是namspace,namespace實際上是存在于xml中,ResultMap是結(jié)果集映射,它的是結(jié)構(gòu)化的,語義上的表現(xiàn)結(jié)構(gòu)是由property與associate,collection組成。這些ONGL語言標簽由mybatis解析。RSTM它對應(yīng)的是一個map容器存在。從另一個角度來說,該框架一部分是語義型,一部分是將語義結(jié)構(gòu)化的部分用組件的方式一一抽離出來的。
它的Id是由上往下一直到parameter組裝的字符串形式。它是放在一個Map容器的。當SqlSessionFactory完成build以后,mybatis需要的config->作用的對象,cache生成,日志形式等就隨著build動作結(jié)束以后完成所有的初始化了。
StatementHandler:處理statement,jdbc基礎(chǔ)知識,可以預處理,存儲過程或函數(shù)處理。
PooledConnection:簡單地實現(xiàn)了連接池,池化的關(guān)鍵是基于線程池創(chuàng)建管理數(shù)據(jù)庫鏈接池,一方面減少線程上下文切換奢侈開支的同時又,另一方面又復用了數(shù)據(jù)庫連接池。它里面會檢測壞的連接池,壞鏈接會專門管理,復活會重新使用。對于它里面的設(shè)計只需要改進連接池隊列和利用aqs來更高的處理就可以演化成一個好用的連接池。
*特性
1.事務(wù)性
2.SQL日志
SQL日志可以用攔截器的方式美化query和update的語句。
3.Plugin特性(指定簽名方法進行攔截,可以實現(xiàn)SQL性能監(jiān)控,分頁,租戶等機制),mybatis支持多個plugin同時存在,沒有嚴格意義上的先后執(zhí)行順序,由定義順序來決定的,業(yè)務(wù)上有需要的場景有:分頁功能,數(shù)據(jù)加密,防止SQL注入,schema鑒定(比如mybatis拿到用戶域以后可以指定用戶的schema,SQL性能監(jiān)控,慢查詢直接中斷查詢,但是就算關(guān)閉鏈接,數(shù)據(jù)庫的任務(wù)也不會終止)
4.緩存機制(namespace層,SqlSession粒度的緩存,一個是作用域在命名空間,一個作用域在session粒度).
關(guān)于緩存,Mybatis里面提供了LRU緩存機制,如果感興趣的朋友可以自行實現(xiàn)。因為緩存不是Mybatis的重要屬性
下面如何添加一個FILO緩存代碼示例
importjava.util.Deque;
importjava.util.LinkedList;
importorg.apache.ibatis.cache.Cache;
/**
* FILO (first in, last out) cache decorator.
*
* @author mybatis
*/
publicclassFifoCacheimplementsCache{
privatefinalCachedelegate;
privatefinalDeque<object style="box-sizing: border-box;">keyList;</object>
privateintsize;
publicFifoCache(Cachedelegate) {
this.delegate=delegate;
this.keyList=newLinkedList<>();
this.size=1024;
}
@Override
publicStringgetId() {
returndelegate.getId();
}
@Override
publicintgetSize() {
returndelegate.getSize();
}
publicvoidsetSize(intsize) {
this.size=size;
}
@Override
publicvoidputObject(Objectkey,Objectvalue) {
cycleKeyList(key);
delegate.putObject(key,value);
}
@Override
publicObjectgetObject(Objectkey) {
returndelegate.getObject(key);
}
@Override
publicObjectremoveObject(Objectkey) {
returndelegate.removeObject(key);
}
@Override
publicvoidclear() {
delegate.clear();
keyList.clear();
}
privatevoidcycleKeyList(Objectkey) {
keyList.addLast(key);
if(keyList.size() >size) {
ObjectoldestKey=keyList.removeLast();
delegate.removeObject(oldestKey);
}
}
}
5.支持ONGL的SQL寫法,支持SqlBuilder以注解形式組裝 寫SQL,然后表現(xiàn)形式 以顯示在方法上
6.支持拓展,比如國產(chǎn)化的Mybatis-Plugin框架,這個框架就是改變MapperBuilder這個內(nèi)部機制的基礎(chǔ)上將單個表的增刪改查方法嵌入在SqlMethod里面了。這個框架還實現(xiàn)了低代碼思想,并支持Stream流式寫法。
7.寫了一個不支持高并發(fā)的鏈接池,低吞吐量用戶量少時可用
一句話結(jié)束
Mybatis是JAVA-Web開發(fā)中國內(nèi)最流行的一套面向數(shù)據(jù)庫開發(fā)的框架,它是一款面向?qū)ο笤O(shè)計思想的框架。簡單易上手,深受廣大各個級別的程序員喜愛。
問:How to designe a new framework that is better than mybatis.
問:What is the lack functions of current mybatis-plugin
問:How to avoid restart the web application when some resources ref mybatis has changed by user
答:定義FileChangeListern事件,監(jiān)聽文件。先找到修改文件對應(yīng)的MapperInterface,指定它重新注入mapper,用MapperRegister重新注冊。