參考:
MyBatis結(jié)構(gòu)和組件 http://www.reibang.com/p/75a6a2297c69
MyBatis運(yùn)行流程炉峰、緩存和插件 http://www.reibang.com/p/4fe280c44294
MyBatis緩存
http://www.reibang.com/p/7a98dda8cd75
http://www.reibang.com/p/8801d1aa20a0
MyBatis常見面試題 https://blog.csdn.net/a745233700/article/details/80977133
一.MyBatis概述
1.MyBatis
- 支持普通SQL查詢蔓搞、存儲(chǔ)過程和高級(jí)映射的持久層框架
- 消除了幾乎所有的JDBC代碼和參數(shù)的手工設(shè)置以及對(duì)結(jié)果集的封裝
- MyBatis可使用XML或注解進(jìn)行配置张足,將接口和Java的POJO映射成數(shù)據(jù)庫(kù)記錄
- 專注于Sql本身,適用于對(duì)性能要求很高或需求變化較多的項(xiàng)目
2.MyBatis特點(diǎn)
- 優(yōu)點(diǎn)
1)簡(jiǎn)單易學(xué)吃媒。MyBatis本身小而簡(jiǎn)單
2)靈活涂籽。MyBatis允許自由編寫Sql語(yǔ)句
3)Sql和程序代碼解耦,且提供xml標(biāo)簽支持編寫動(dòng)態(tài)sql
4)提供映射標(biāo)簽毅否,支持對(duì)象與數(shù)據(jù)庫(kù)的ORM字段關(guān)系映射
5)與JDBC相比亚铁,減少了50%以上的代碼量 - 缺點(diǎn)
1)自由編寫Sql語(yǔ)句意味較大的工作量
2)Sql語(yǔ)句依賴于數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)無法隨意更換搀突,移植性差
二.MyBatis原理
1.MyBatis功能結(jié)構(gòu)
- API接口層
開發(fā)人員通過接口API操縱數(shù)據(jù)庫(kù)刀闷,接口層接收請(qǐng)求后會(huì)調(diào)用數(shù)據(jù)處理層完成具體的數(shù)據(jù)處理 - 數(shù)據(jù)處理層
根據(jù)API接口層調(diào)用的請(qǐng)求完成一次數(shù)據(jù)庫(kù)操作熊泵,負(fù)責(zé)具體的Sql查找、Sql解析和執(zhí)行結(jié)果映射處理等 - 基礎(chǔ)支撐層
實(shí)現(xiàn)連接管理甸昏、事務(wù)管理和執(zhí)行結(jié)果映射處理等基礎(chǔ)功能顽分,為數(shù)據(jù)處理層提供基礎(chǔ)支持
2.MyBatis運(yùn)行流程
- 加載配置
從配置文件或注解獲取配置信息并加載成MappedStatement
對(duì)象,此對(duì)象=傳入?yún)?shù)的映射配置+要執(zhí)行的Sql語(yǔ)句+結(jié)果的映射配置 - Sql解析
API接口層接收調(diào)用請(qǐng)求時(shí)施蜜,根據(jù)傳入的Sql的Id找到對(duì)應(yīng)的MappedStatement
卒蘸,再根據(jù)傳入的參數(shù)對(duì)象解析MappedStatement
,獲得最終要執(zhí)行的Sql語(yǔ)句和參數(shù) - Sql執(zhí)行
獲取數(shù)據(jù)庫(kù)連接翻默,執(zhí)行Sql解析獲得的Sql語(yǔ)句和參數(shù)缸沃,并返回結(jié)果 - 結(jié)果映射
將數(shù)據(jù)庫(kù)返回結(jié)果按映射配置轉(zhuǎn)換成需要的數(shù)據(jù)類型并返回
3.MyBatis主要構(gòu)件
-
SqlSession
MyBatis主要頂層API,負(fù)責(zé)和數(shù)據(jù)庫(kù)交互的會(huì)話修械,完成增刪查改操作 -
Executor
MyBatis執(zhí)行器趾牧,是MyBatis調(diào)度和核心,負(fù)責(zé)Sql語(yǔ)句生成和查詢緩存的維護(hù) -
StatementHandler
封裝了JDBC Statement肯污,負(fù)責(zé)JDBC中對(duì)Statement的操作翘单,如設(shè)置參數(shù)、將Statement結(jié)果集轉(zhuǎn)換為L(zhǎng)ist集合 -
ParameterHandler
將用戶傳遞的參數(shù)轉(zhuǎn)換為JDBC Statement所需的參數(shù) -
ResultSetHandler
將JDBC返回的ResultSet結(jié)果集轉(zhuǎn)換為L(zhǎng)ist集合 -
TypeHandler
負(fù)責(zé)Java數(shù)據(jù)類型和JDBC數(shù)據(jù)類型間的映射和轉(zhuǎn)換 -
MappedStatement
維護(hù)<select/update/delete/insert>節(jié)點(diǎn)的封裝 -
SqlSource
根據(jù)用戶傳遞的parameterObject蹦渣,動(dòng)態(tài)生成Sql語(yǔ)句哄芜,將信息封裝到BoundSql對(duì)象并返回 -
BoundSql
表示動(dòng)態(tài)生成的Sql語(yǔ)句及相應(yīng)的參數(shù)信息 -
Configuration
維持MyBatis所有的配置信息
三.MyBatis緩存
1.緩存總覽
- 緩存在流程的Executor使用,Executor執(zhí)行查詢時(shí)先判斷緩存柬唯,若緩存命中认臊,直接返回緩存中的結(jié)果,否則繼續(xù)之后的步驟查詢數(shù)據(jù)庫(kù)
- MyBatis使用底層為HashMap的Cache對(duì)象锄奢,通過各種裝飾類對(duì)其層層裝飾失晴,以實(shí)現(xiàn)各種功能和隔離不同功能邏輯
- MyBatis緩存分為一級(jí)緩存和二級(jí)緩存,默認(rèn)開啟一級(jí)緩存
- 數(shù)據(jù)查詢優(yōu)先級(jí):二級(jí)緩存---一級(jí)緩存---數(shù)據(jù)庫(kù)
2.一級(jí)緩存
- 緩存默認(rèn)Session級(jí)別(可設(shè)為Statement)拘央,同一會(huì)話的重復(fù)Sql語(yǔ)句可使用緩存
- 不同Session間緩存相互獨(dú)立师坎,分布式查詢可能讀到臟數(shù)據(jù)
- Executor收到Sql語(yǔ)句后飒泻,先查詢自己的localCache(HashMap)渴频,緩存命中則直接返回結(jié)果珊搀,緩存命中失敗則繼續(xù)查詢數(shù)據(jù)庫(kù)后將結(jié)果寫入localCache
3.二級(jí)緩存
- 為解決跨SqlSession的緩存問題,MyBatis提供二級(jí)緩存功能
- 二級(jí)緩存使用CachingExecutor包裝Executor袱箱,CachingExecutor負(fù)責(zé)與全局二級(jí)緩存交互
- CachingExecutor優(yōu)先查詢二級(jí)緩存,如沒有匹配則委托給它包裝的Executor匹配的一級(jí)緩存
- 二級(jí)緩存全局有效义矛,劃分到mapper級(jí)別(namespace定義)发笔,而非整個(gè)application使用同一緩存
- 由于不同namespace的二級(jí)緩存相互獨(dú)立,多表查詢時(shí)容易出現(xiàn)臟數(shù)據(jù)凉翻。如果將多個(gè)表的操作放在相同namespace會(huì)導(dǎo)致緩存顆粒度過大了讨,頻繁刷新緩存
- MyBatis Cache是基于本地的,分布式環(huán)境下必然會(huì)讀取臟數(shù)據(jù),用戶自定義實(shí)現(xiàn)MyBatis的Cache接口開發(fā)成本較高前计,直接使用Redis/Memcached等分布式緩存成本更低胞谭,安全性更高
四.MyBatis插件
1.插件概述
- MyBatis插件又稱攔截器,采用責(zé)任鏈模式男杈,通過動(dòng)態(tài)代理組織多個(gè)插件(攔截器)丈屹,改變MyBatis默認(rèn)行為(如Sql重寫)
- 插件通過動(dòng)態(tài)代理方式在已映射語(yǔ)句執(zhí)行過程中的某一點(diǎn)進(jìn)行攔截調(diào)用
- MyBatis插件需要實(shí)現(xiàn)Interceptor接口,該接口主要方法有
1)setProperties
:配置MyBatis插件的自定義屬性
2)plugin
:插件用來封裝目標(biāo)對(duì)象的方法伶棒,通過該方法可返回目標(biāo)對(duì)象本身或一個(gè)它的代理
3)interceptor
:攔截時(shí)執(zhí)行的方法
4)plugin
接口
五.MyBatis與其他框架
1.MyBatis與iBatis
- iBatis是Apache的一個(gè)開源項(xiàng)目旺垒,該項(xiàng)目在2010年從Apache Software Foundation遷移到Google Code,并改名MyBatis
- MyBatis是IBatis的升級(jí)版肤无,MyBatis在以下方面改善了IBatis功能
1)MyBatis實(shí)現(xiàn)接口綁定先蒋,使用更方便
2)MyBatis改進(jìn)了對(duì)象關(guān)系映射(association和collection)
3)MyBatis在動(dòng)態(tài)Sql語(yǔ)句中采用OGNL表達(dá)式取代節(jié)點(diǎn)配置
2.MyBatis與Hibernate
- MyBatis
1)Mybatis真正實(shí)現(xiàn)了Java代碼和Sql分離
2)Mybatis自行編寫sql,靈活度高宛渐,便于Sql優(yōu)化 - Hibernate
1)Hibernate數(shù)據(jù)庫(kù)無關(guān)性好竞漾,適用于需求固定的定制化軟件,但學(xué)習(xí)成本高
2)Hibernate大大降低了對(duì)象和數(shù)據(jù)庫(kù)的耦合度皇忿,其數(shù)據(jù)移植性遠(yuǎn)大于MyBatis
3)Hibernate在多表關(guān)聯(lián)查詢時(shí)表現(xiàn)較差
4)Hibernate效率較低畴蹭,Sql自動(dòng)生成,不便于人工優(yōu)化鳍烁,調(diào)優(yōu)需要相當(dāng)經(jīng)驗(yàn)積累 - 場(chǎng)景選擇
1)數(shù)據(jù)量大(超過千萬級(jí)別的表/單次業(yè)務(wù)大批量數(shù)據(jù)(百萬條)提交或讀取)適用MyBatis
2)表關(guān)聯(lián)度(主要業(yè)務(wù)表的關(guān)聯(lián)表>20)復(fù)雜適用MyBatis
六.常見面試題
1.SqlSession創(chuàng)建過程和相關(guān)對(duì)象生命周期叨襟?
SqlSessionFactoryBuilder
---SqlSessionFactory
---SqlSession
---SqlMapper
-
SqlSessionFactoryBuilder
在構(gòu)建SqlSessionFactory
后即可銷毀 -
SqlSessionFactory
存在于整個(gè)MyBatis應(yīng)用中,類似數(shù)據(jù)庫(kù)連接池幔荒,不斷創(chuàng)建SqlSession
-
SqlSession
類似于數(shù)據(jù)庫(kù)連接糊闽,在完成一次業(yè)務(wù)請(qǐng)求后回收 -
SqlMapper
由SqlSession
創(chuàng)建,生命周期SqlMapper
<=SqlSession
2.#{}和${}的區(qū)別爹梁?
- 前者’#{}‘是預(yù)編譯處理右犹,MyBatis預(yù)編譯時(shí)會(huì)將#{}替換為?號(hào),調(diào)用PreparedStatement的set方法賦值
- 后者是xml文件的字符串替換姚垃,MyBatis會(huì)把${}替換成變量的值
- 使用#{}可防止Sql注入念链,提高安全性
3.實(shí)體類的屬性名和表中字段名不一樣該如何映射?
- 在Sql語(yǔ)句中定義與實(shí)體類屬性名一樣的別名
- 通過<resultMap>映射字段名和實(shí)體類屬性名
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!–用id屬性來映射主鍵字段–>
<id property=”id” column=”order_id”>
<!–用result屬性來映射非主鍵字段积糯,property為實(shí)體類屬性名掂墓,column為數(shù)據(jù)表中的屬性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
4.每個(gè)xml映射文件都有一個(gè)Dao接口與之對(duì)應(yīng),Dao接口的工作原理是什么看成?Dao接口里的方法在參數(shù)不同時(shí)是否可以重載君编?
- Dao接口即Mapper接口:映射的xml文件的namespace是接口的全限定名;映射文件中MappedStatement的id是接口的方法名川慌;接口方法的參數(shù)就是傳遞給sql的參數(shù)
- 調(diào)用接口方法時(shí)吃嘿,通過接口全限定名+方法名定位唯一的MappedStatement
- 由于僅使用接口全限定名和方法名定位MappedStatement祠乃,故不同參數(shù)的接口方法不能重載
- 此外,不同的xml配置文件兑燥,如果設(shè)置不同的namespace亮瓷,則id可重復(fù),否則不可重復(fù)
5.MyBatis是如何進(jìn)行分頁(yè)的贪嫂?分頁(yè)插件的原理是什么寺庄?
- MyBatis使用RowBounds對(duì)象針對(duì)ResultSet結(jié)果集執(zhí)行內(nèi)存分頁(yè),也可以在Sql內(nèi)直接書寫帶有物理分頁(yè)的參數(shù)實(shí)現(xiàn)物理分頁(yè)
- 分頁(yè)插件實(shí)現(xiàn)MyBatis提供的插件接口力崇,在插件的攔截方法里攔截并重寫待執(zhí)行的sql
6.MyBatis動(dòng)態(tài)Sql是做什么的斗塘?其執(zhí)行原理是什么?
- MyBatis允許在xml映射文件中以標(biāo)簽形式編寫動(dòng)態(tài)Sql亮靴,完成邏輯判斷和動(dòng)態(tài)拼接Sql的功能
- MyBatis提供 trim | where | set | foreach | if | choose | when | otherwise | bid 9種動(dòng)態(tài)sql標(biāo)簽
- 執(zhí)行原理為
1)使用OGNL從sql參數(shù)對(duì)象中計(jì)算表達(dá)式的值
2)根據(jù)表達(dá)式值動(dòng)態(tài)拼接Sql
7.MyBatis是否支持延遲加載馍盟?其實(shí)現(xiàn)原理是什么?
- 延遲加載又稱懶加載茧吊,用于處理N+1性能問題
- N+1問題指映射集合(resultMap)級(jí)聯(lián)時(shí)贞岭,我們需要的數(shù)據(jù)少于數(shù)據(jù)庫(kù)查出的數(shù)據(jù),浪費(fèi)性能且加重?cái)?shù)據(jù)庫(kù)負(fù)擔(dān)
- MyBatis僅支持association關(guān)聯(lián)對(duì)象(1對(duì)1)和collection關(guān)聯(lián)集合(1對(duì)多)的延遲加載搓侄,配置文件中參數(shù)LazyLoadingEnabled=true|false設(shè)置是否開啟延遲加載
- MyBatis通過動(dòng)態(tài)代理實(shí)現(xiàn)延遲加載
參考:https://my.oschina.net/wenjinglian/blog/1857581?from=singlemessage
8.使用MyBatis的mapper接口調(diào)用時(shí)有哪些要求瞄桨?
- Mapper接口方法名和mapper.xml定義的sql的id相同
- Mapper接口方法的輸入?yún)?shù)類型和mapper.xml定義的sql的parameterType類型相同
- Mapper接口方法的輸出參數(shù)類型和mapper.xml定義的sql的resultType類型相同
- Mapper.xml的namespace即是mapper接口的類路徑
9.mapper有哪幾種編寫方式?
- 接口實(shí)現(xiàn)類繼承SqlSessionDaoSupport類
- 使用org.mybatis.spring.mapper.MapperFactoryBean
- 使用mapper掃描器
10.mapper如何傳遞多個(gè)參數(shù)讶踪?
- xml使用#{0}接收dao層第一個(gè)參數(shù)芯侥,#{1}接收第二個(gè)參數(shù),以此類推
- 使用@param注解