詳解MyBatis延遲加載是如何實(shí)現(xiàn)的
引言
MyBatis 的延遲加載(懶加載)特性允許在需要使用關(guān)聯(lián)對(duì)象數(shù)據(jù)時(shí)才進(jìn)行加載,而不是在執(zhí)行主查詢(xún)時(shí)就加載所有相關(guān)數(shù)據(jù)。這種機(jī)制可以提高應(yīng)用程序的性能,特別是當(dāng)關(guān)聯(lián)數(shù)據(jù)龐大或關(guān)聯(lián)層次較深時(shí)。我們將通過(guò)以下幾個(gè)方面來(lái)深入了解MyBatis的延遲加載實(shí)現(xiàn)機(jī)制。
配置延遲加載
要在MyBatis中啟用延遲加載,需要在配置文件mybatis-config.xml
中進(jìn)行相關(guān)設(shè)置:
<settings> <!-- 開(kāi)啟全局的延遲加載 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 將積極加載改為消極加載(即延遲加載) --> <setting name="aggressiveLazyLoading" value="false"/> <!-- 當(dāng)開(kāi)啟延遲加載時(shí),每個(gè)屬性都會(huì)延遲加載 --> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> </settings>
lazyLoadingEnabled
控制是否啟用延遲加載。aggressiveLazyLoading
控制是否對(duì)所有關(guān)聯(lián)對(duì)象進(jìn)行加載,設(shè)置為false
可以避免加載不必要的關(guān)聯(lián)對(duì)象。lazyLoadTriggerMethods
指定哪些方法觸發(fā)加載屬性,通常保持默認(rèn)即可。
實(shí)現(xiàn)原理
MyBatis 的延遲加載主要依賴(lài)于代理對(duì)象。當(dāng)配置了延遲加載后,MyBatis 會(huì)為需要延遲加載的屬性生成一個(gè)代理對(duì)象,當(dāng)訪(fǎng)問(wèn)這個(gè)屬性時(shí),代理對(duì)象負(fù)責(zé)執(zhí)行實(shí)際的加載操作。
步驟概述
- 結(jié)果映射: 在結(jié)果映射時(shí),對(duì)于配置了延遲加載的關(guān)聯(lián)屬性,MyBatis 不會(huì)立即執(zhí)行關(guān)聯(lián)查詢(xún),而是為該屬性創(chuàng)建一個(gè)代理對(duì)象。
- 代理觸發(fā): 當(dāng)訪(fǎng)問(wèn)這個(gè)屬性的方法時(shí),比如
get
方法,代理對(duì)象會(huì)觸發(fā)實(shí)際的關(guān)聯(lián)查詢(xún)。 - 查詢(xún)加載: 代理對(duì)象執(zhí)行關(guān)聯(lián)查詢(xún),并將查詢(xún)結(jié)果設(shè)置到目標(biāo)對(duì)象的屬性中,替換掉自身。
代碼演示
以一對(duì)多關(guān)系為例,配置延遲加載:
<resultMap id="blogResultMap" type="Blog"> <collection property="posts" ofType="Post" select="selectPostsForBlog" column="id" fetchType="lazy"/> </resultMap> <select id="selectBlog" resultMap="blogResultMap"> SELECT * FROM blog WHERE id = #{id} </select> <select id="selectPostsForBlog" parameterType="int" resultType="Post"> SELECT * FROM post WHERE blog_id = #{id} </select>
這里,<collection>
中的 fetchType="lazy"
指示MyBatis為 posts
屬性創(chuàng)建代理對(duì)象,以實(shí)現(xiàn)延遲加載。
源碼解析
在MyBatis中,延遲加載的實(shí)現(xiàn)涉及到以下幾個(gè)關(guān)鍵類(lèi):
SqlSessionManager
: 作為SQL會(huì)話(huà)的管理器,它負(fù)責(zé)創(chuàng)建SqlSession
。Configuration
: 包含了MyBatis的所有配置信息,包括延遲加載的設(shè)置。Executor
: 執(zhí)行器,負(fù)責(zé)執(zhí)行SQL命令,延遲加載的觸發(fā)最終會(huì)調(diào)用執(zhí)行器來(lái)執(zhí)行關(guān)聯(lián)查詢(xún)。ProxyFactory
: 代理工廠(chǎng),用于創(chuàng)建延遲加載的代理對(duì)象。
延遲加載的代理對(duì)象主要通過(guò)Java的動(dòng)態(tài)代理實(shí)現(xiàn)。在訪(fǎng)問(wèn)代理對(duì)象的方法時(shí),動(dòng)態(tài)代理會(huì)攔截這個(gè)調(diào)用,并判斷是否需要觸發(fā)延遲加載。如果需要,則執(zhí)行實(shí)際的查詢(xún)并加載數(shù)據(jù),然后將結(jié)果設(shè)置到目標(biāo)對(duì)象中。
以下是一個(gè)簡(jiǎn)化的示例來(lái)說(shuō)明代理對(duì)象如何攔截方法調(diào)用并觸發(fā)加載:
public class LazyLoadingProxy implements InvocationHandler { private Object target; private boolean loaded; public LazyLoadingProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (!loaded && isLoadMethod(method)) { loadObject(); loaded = true; } return method.invoke(target, args); } private boolean isLoadMethod(Method method) { // 判斷方法是否觸發(fā)加載 return "getPosts".equals(method.getName()); } private void loadObject() { // 執(zhí)行加載邏輯,比如執(zhí)行SQL查詢(xún) } }
在上面的代碼中,LazyLoadingProxy
是一個(gè)動(dòng)態(tài)代理類(lèi),它在方法調(diào)用時(shí)判斷是否需要加載數(shù)據(jù),并在必要時(shí)進(jìn)行加載。這個(gè)簡(jiǎn)化的例子演示了延遲加載的基本思想。
總結(jié)
MyBatis的延遲加載特性通過(guò)動(dòng)態(tài)代理和配置控制,實(shí)現(xiàn)了按需加載關(guān)聯(lián)數(shù)據(jù)的能力。通過(guò)延遲加載,可以?xún)?yōu)化應(yīng)用程序的性能,特別是在處理復(fù)雜關(guān)系和大量數(shù)據(jù)時(shí)。雖然延遲加載增加了實(shí)現(xiàn)的復(fù)雜度,但MyBatis通過(guò)提供靈活的配置和強(qiáng)大的映射機(jī)制,使得管理這種復(fù)雜度成為可能。
以上就是詳解MyBatis延遲加載是如何實(shí)現(xiàn)的的詳細(xì)內(nèi)容,更多關(guān)于MyBatis延遲加載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- MyBatis高級(jí)映射學(xué)習(xí)教程
- MyBatis高級(jí)映射和查詢(xún)緩存
- Mybatis高級(jí)映射、動(dòng)態(tài)SQL及獲得自增主鍵的解析
- mybatis高級(jí)映射一對(duì)多查詢(xún)實(shí)現(xiàn)代碼
- 基于mybatis高級(jí)映射多對(duì)多查詢(xún)的實(shí)現(xiàn)
- javaMybatis映射屬性,高級(jí)映射詳解
- 解析Mybatis延遲加載問(wèn)題
- MyBatis延遲加載與立即加載案例教程
- MyBatis高級(jí)映射ResultMap解決屬性問(wèn)題
- Mybatis中的延遲加載,以及原理分析
- MyBatis實(shí)現(xiàn)高級(jí)映射的示例代碼
- MyBatis高級(jí)映射及延遲加載的實(shí)現(xiàn)
相關(guān)文章
java8升級(jí)到j(luò)ava17的兼容性分析與遷移指南
這篇文章主要為大家詳細(xì)介紹了從?Java?8?升級(jí)到?Java?17?的詳細(xì)分析和遷移步驟,包括代碼修改建議,依賴(lài)更新和配置調(diào)整,有需要的小伙伴可以參考一下2025-04-04解決IntelliJ IDEA 控制臺(tái)輸出中文亂碼問(wèn)題(史上最簡(jiǎn)單)
這篇文章主要介紹了史上最簡(jiǎn)單的IntelliJ IDEA 控制臺(tái)輸出中文亂碼問(wèn)題的解決方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-05-05SpringBoot項(xiàng)目啟動(dòng)后再請(qǐng)求遠(yuǎn)程接口的解決方式
Spring?Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化Spring應(yīng)用的創(chuàng)建、運(yùn)行、調(diào)試、部署等,這篇文章主要介紹了SpringBoot項(xiàng)目啟動(dòng)后再請(qǐng)求遠(yuǎn)程接口的實(shí)現(xiàn)方式?,需要的朋友可以參考下2023-02-02mybatis-plus中更新null值的問(wèn)題解決
本文主要介紹 mybatis-plus 中常使用的 update 相關(guān)方法的區(qū)別,以及更新 null 的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-04-04Spring WebFlux實(shí)現(xiàn)參數(shù)校驗(yàn)的示例代碼
請(qǐng)求參數(shù)校驗(yàn),在實(shí)際的應(yīng)用中很常見(jiàn),網(wǎng)上的文章大部分提供的使用注解的方式做參數(shù)校驗(yàn)。本文主要介紹 Spring Webflux Function Endpoint 使用 Spring Validation 來(lái)校驗(yàn)請(qǐng)求的參數(shù)。感興趣的可以了解一下2021-08-08Spring boot 跳轉(zhuǎn)到j(luò)sp頁(yè)面的實(shí)現(xiàn)方法
本篇文章主要介紹了Spring boot 跳轉(zhuǎn)到j(luò)sp頁(yè)面的實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04Springboot實(shí)現(xiàn)緩存預(yù)熱的方法
在系統(tǒng)啟動(dòng)之前通過(guò)預(yù)先將常用數(shù)據(jù)加載到緩存中,以提高緩存命中率和系統(tǒng)性能的過(guò)程,緩存預(yù)熱的目的是盡可能地避免緩存擊穿和緩存雪崩,這篇文章主要介紹了Springboot實(shí)現(xiàn)緩存預(yù)熱,需要的朋友可以參考下2024-03-03SpringBoot 請(qǐng)求參數(shù)忽略大小寫(xiě)的實(shí)例
這篇文章主要介紹了SpringBoot 請(qǐng)求參數(shù)忽略大小寫(xiě)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-01-01Idea安裝及涉及springboot詳細(xì)配置的圖文教程
這篇文章主要介紹了Idea安裝及涉及springboot詳細(xì)配置,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10