框架2 MyBatis

參考:
MyBatis結(jié)構(gòu)和組件 http://www.itdecent.cn/p/75a6a2297c69
MyBatis運行流程、緩存和插件 http://www.itdecent.cn/p/4fe280c44294
MyBatis緩存
http://www.itdecent.cn/p/7a98dda8cd75
http://www.itdecent.cn/p/8801d1aa20a0
MyBatis常見面試題 https://blog.csdn.net/a745233700/article/details/80977133

一.MyBatis概述

1.MyBatis
  • 支持普通SQL查詢、存儲過程和高級映射的持久層框架
  • 消除了幾乎所有的JDBC代碼和參數(shù)的手工設(shè)置以及對結(jié)果集的封裝
  • MyBatis可使用XML或注解進(jìn)行配置,將接口和Java的POJO映射成數(shù)據(jù)庫記錄
  • 專注于Sql本身,適用于對性能要求很高或需求變化較多的項目
2.MyBatis特點
  • 優(yōu)點
    1)簡單易學(xué)。MyBatis本身小而簡單
    2)靈活。MyBatis允許自由編寫Sql語句
    3)Sql和程序代碼解耦,且提供xml標(biāo)簽支持編寫動態(tài)sql
    4)提供映射標(biāo)簽,支持對象與數(shù)據(jù)庫的ORM字段關(guān)系映射
    5)與JDBC相比,減少了50%以上的代碼量
  • 缺點
    1)自由編寫Sql語句意味較大的工作量
    2)Sql語句依賴于數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫無法隨意更換,移植性差

二.MyBatis原理

1.MyBatis功能結(jié)構(gòu)
  • API接口層
    開發(fā)人員通過接口API操縱數(shù)據(jù)庫,接口層接收請求后會調(diào)用數(shù)據(jù)處理層完成具體的數(shù)據(jù)處理
  • 數(shù)據(jù)處理層
    根據(jù)API接口層調(diào)用的請求完成一次數(shù)據(jù)庫操作,負(fù)責(zé)具體的Sql查找、Sql解析和執(zhí)行結(jié)果映射處理等
  • 基礎(chǔ)支撐層
    實現(xiàn)連接管理、事務(wù)管理和執(zhí)行結(jié)果映射處理等基礎(chǔ)功能,為數(shù)據(jù)處理層提供基礎(chǔ)支持
MyBatis功能結(jié)構(gòu)
2.MyBatis運行流程
  • 加載配置
    從配置文件或注解獲取配置信息并加載成MappedStatement對象,此對象=傳入?yún)?shù)的映射配置+要執(zhí)行的Sql語句+結(jié)果的映射配置
  • Sql解析
    API接口層接收調(diào)用請求時,根據(jù)傳入的Sql的Id找到對應(yīng)的MappedStatement,再根據(jù)傳入的參數(shù)對象解析MappedStatement,獲得最終要執(zhí)行的Sql語句和參數(shù)
  • Sql執(zhí)行
    獲取數(shù)據(jù)庫連接執(zhí)行Sql解析獲得的Sql語句和參數(shù),并返回結(jié)果
  • 結(jié)果映射
    將數(shù)據(jù)庫返回結(jié)果按映射配置轉(zhuǎn)換成需要的數(shù)據(jù)類型并返回
MyBatis運行流程
3.MyBatis主要構(gòu)件
  • SqlSession
    MyBatis主要頂層API,負(fù)責(zé)和數(shù)據(jù)庫交互的會話,完成增刪查改操作
  • Executor
    MyBatis執(zhí)行器,是MyBatis調(diào)度和核心,負(fù)責(zé)Sql語句生成和查詢緩存的維護(hù)
  • StatementHandler
    封裝了JDBC Statement,負(fù)責(zé)JDBC中對Statement的操作,如設(shè)置參數(shù)、將Statement結(jié)果集轉(zhuǎn)換為List集合
  • ParameterHandler
    將用戶傳遞的參數(shù)轉(zhuǎn)換為JDBC Statement所需的參數(shù)
  • ResultSetHandler
    將JDBC返回的ResultSet結(jié)果集轉(zhuǎn)換為List集合
  • TypeHandler
    負(fù)責(zé)Java數(shù)據(jù)類型和JDBC數(shù)據(jù)類型間的映射和轉(zhuǎn)換
  • MappedStatement
    維護(hù)<select/update/delete/insert>節(jié)點的封裝
  • SqlSource
    根據(jù)用戶傳遞的parameterObject,動態(tài)生成Sql語句,將信息封裝到BoundSql對象并返回
  • BoundSql
    表示動態(tài)生成的Sql語句及相應(yīng)的參數(shù)信息
  • Configuration
    維持MyBatis所有的配置信息
MyBatis主要組件及其相互關(guān)系

三.MyBatis緩存

1.緩存總覽
MyBatis流程圖
  • 緩存在流程的Executor使用,Executor執(zhí)行查詢時先判斷緩存,若緩存命中,直接返回緩存中的結(jié)果,否則繼續(xù)之后的步驟查詢數(shù)據(jù)庫
  • MyBatis使用底層為HashMap的Cache對象,通過各種裝飾類對其層層裝飾,以實現(xiàn)各種功能和隔離不同功能邏輯
  • MyBatis緩存分為一級緩存二級緩存,默認(rèn)開啟一級緩存
  • 數(shù)據(jù)查詢優(yōu)先級:二級緩存---一級緩存---數(shù)據(jù)庫
2.一級緩存
  • 緩存默認(rèn)Session級別(可設(shè)為Statement),同一會話的重復(fù)Sql語句可使用緩存
  • 不同Session間緩存相互獨立,分布式查詢可能讀到臟數(shù)據(jù)
  • Executor收到Sql語句后,先查詢自己的localCache(HashMap),緩存命中則直接返回結(jié)果,緩存命中失敗則繼續(xù)查詢數(shù)據(jù)庫后將結(jié)果寫入localCache
3.二級緩存
  • 解決跨SqlSession的緩存問題,MyBatis提供二級緩存功能
  • 二級緩存使用CachingExecutor包裝Executor,CachingExecutor負(fù)責(zé)與全局二級緩存交互
二級緩存流程圖
  • CachingExecutor優(yōu)先查詢二級緩存,如沒有匹配則委托給它包裝的Executor匹配的一級緩存
Executor
  • 二級緩存全局有效,劃分到mapper級別(namespace定義),而非整個application使用同一緩存
  • 由于不同namespace的二級緩存相互獨立,多表查詢時容易出現(xiàn)臟數(shù)據(jù)。如果將多個表的操作放在相同namespace會導(dǎo)致緩存顆粒度過大,頻繁刷新緩存
  • MyBatis Cache是基于本地的,分布式環(huán)境下必然會讀取臟數(shù)據(jù),用戶自定義實現(xiàn)MyBatis的Cache接口開發(fā)成本較高,直接使用Redis/Memcached等分布式緩存成本更低,安全性更高

四.MyBatis插件

1.插件概述
  • MyBatis插件又稱攔截器,采用責(zé)任鏈模式,通過動態(tài)代理組織多個插件(攔截器),改變MyBatis默認(rèn)行為(如Sql重寫)
  • 插件通過動態(tài)代理方式在已映射語句執(zhí)行過程中的某一點進(jìn)行攔截調(diào)用
  • MyBatis插件需要實現(xiàn)Interceptor接口,該接口主要方法有
    1)setProperties:配置MyBatis插件的自定義屬性
    2)plugin:插件用來封裝目標(biāo)對象的方法,通過該方法可返回目標(biāo)對象本身或一個它的代理
    3)interceptor:攔截時執(zhí)行的方法
    4)plugin接口

五.MyBatis與其他框架

1.MyBatis與iBatis
  • iBatis是Apache的一個開源項目,該項目在2010年從Apache Software Foundation遷移到Google Code,并改名MyBatis
  • MyBatis是IBatis的升級版,MyBatis在以下方面改善了IBatis功能
    1)MyBatis實現(xiàn)接口綁定,使用更方便
    2)MyBatis改進(jìn)了對象關(guān)系映射(association和collection)
    3)MyBatis在動態(tài)Sql語句中采用OGNL表達(dá)式取代節(jié)點配置
2.MyBatis與Hibernate
  • MyBatis
    1)Mybatis真正實現(xiàn)了Java代碼和Sql分離
    2)Mybatis自行編寫sql,靈活度高,便于Sql優(yōu)化
  • Hibernate
    1)Hibernate數(shù)據(jù)庫無關(guān)性好,適用于需求固定的定制化軟件,但學(xué)習(xí)成本高
    2)Hibernate大大降低了對象和數(shù)據(jù)庫的耦合度,其數(shù)據(jù)移植性遠(yuǎn)大于MyBatis
    3)Hibernate在多表關(guān)聯(lián)查詢時表現(xiàn)較差
    4)Hibernate效率較低,Sql自動生成,不便于人工優(yōu)化,調(diào)優(yōu)需要相當(dāng)經(jīng)驗積累
  • 場景選擇
    1)數(shù)據(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)對象生命周期?
  • SqlSessionFactoryBuilder---SqlSessionFactory---SqlSession---SqlMapper
  • SqlSessionFactoryBuilder在構(gòu)建SqlSessionFactory后即可銷毀
  • SqlSessionFactory存在于整個MyBatis應(yīng)用中,類似數(shù)據(jù)庫連接池,不斷創(chuàng)建SqlSession
  • SqlSession類似于數(shù)據(jù)庫連接,在完成一次業(yè)務(wù)請求后回收
  • SqlMapperSqlSession創(chuàng)建,生命周期SqlMapper<=SqlSession
2.#{}和${}的區(qū)別?
  • 前者’#{}‘是預(yù)編譯處理,MyBatis預(yù)編譯時會將#{}替換為?號,調(diào)用PreparedStatement的set方法賦值
  • 后者是xml文件的字符串替換,MyBatis會把${}替換成變量的值
  • 使用#{}可防止Sql注入,提高安全性
3.實體類的屬性名和表中字段名不一樣該如何映射?
  • 在Sql語句中定義與實體類屬性名一樣的別名
  • 通過<resultMap>映射字段名和實體類屬性名
    <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為實體類屬性名,column為數(shù)據(jù)表中的屬性–>
        <result property = “orderno” column =”order_no”/>
        <result property=”price” column=”order_price” />
    </reslutMap>
4.每個xml映射文件都有一個Dao接口與之對應(yīng),Dao接口的工作原理是什么?Dao接口里的方法在參數(shù)不同時是否可以重載?
  • Dao接口即Mapper接口:映射的xml文件的namespace接口的全限定名;映射文件中MappedStatement的id接口的方法名;接口方法的參數(shù)就是傳遞給sql的參數(shù)
  • 調(diào)用接口方法時,通過接口全限定名+方法名定位唯一的MappedStatement
  • 由于僅使用接口全限定名和方法名定位MappedStatement,故不同參數(shù)的接口方法不能重載
  • 此外,不同的xml配置文件,如果設(shè)置不同的namespace,則id可重復(fù),否則不可重復(fù)
5.MyBatis是如何進(jìn)行分頁的?分頁插件的原理是什么?
  • MyBatis使用RowBounds對象針對ResultSet結(jié)果集執(zhí)行內(nèi)存分頁,也可以在Sql內(nèi)直接書寫帶有物理分頁的參數(shù)實現(xiàn)物理分頁
  • 分頁插件實現(xiàn)MyBatis提供的插件接口,在插件的攔截方法里攔截并重寫待執(zhí)行的sql
6.MyBatis動態(tài)Sql是做什么的?其執(zhí)行原理是什么?
  • MyBatis允許在xml映射文件中以標(biāo)簽形式編寫動態(tài)Sql,完成邏輯判斷和動態(tài)拼接Sql的功能
  • MyBatis提供 trim | where | set | foreach | if | choose | when | otherwise | bid 9種動態(tài)sql標(biāo)簽
  • 執(zhí)行原理為
    1)使用OGNL從sql參數(shù)對象中計算表達(dá)式的值
    2)根據(jù)表達(dá)式值動態(tài)拼接Sql
7.MyBatis是否支持延遲加載?其實現(xiàn)原理是什么?
  • 延遲加載又稱懶加載,用于處理N+1性能問題
  • N+1問題指映射集合(resultMap)級聯(lián)時,我們需要的數(shù)據(jù)少于數(shù)據(jù)庫查出的數(shù)據(jù),浪費性能且加重數(shù)據(jù)庫負(fù)擔(dān)
  • MyBatis僅支持association關(guān)聯(lián)對象(1對1)和collection關(guān)聯(lián)集合(1對多)的延遲加載,配置文件中參數(shù)LazyLoadingEnabled=true|false設(shè)置是否開啟延遲加載
  • MyBatis通過動態(tài)代理實現(xiàn)延遲加載
    參考:https://my.oschina.net/wenjinglian/blog/1857581?from=singlemessage
8.使用MyBatis的mapper接口調(diào)用時有哪些要求?
  • 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有哪幾種編寫方式?
  • 接口實現(xiàn)類繼承SqlSessionDaoSupport類
  • 使用org.mybatis.spring.mapper.MapperFactoryBean
  • 使用mapper掃描器
10.mapper如何傳遞多個參數(shù)?
  • xml使用#{0}接收dao層第一個參數(shù),#{1}接收第二個參數(shù),以此類推
  • 使用@param注解
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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