最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mybatis中的延遲加載和一二級緩存深入解析

 更新時間:2025年12月02日 11:19:44   作者:不光頭強  
延遲加載是MyBatis對關(guān)聯(lián)查詢的優(yōu)化機制,查詢主對象時,不立即查詢其關(guān)聯(lián)對象(如用戶和賬戶的一對多關(guān)系),僅在實際使用關(guān)聯(lián)對象(調(diào)用 getter 方法)時,才觸發(fā)關(guān)聯(lián)查詢的 SQL 執(zhí)行,這篇文章給大家介紹mybatis中的延遲加載和一二級緩存,感興趣的朋友一起看看吧

MyBatis 延遲加載與一二級緩存核心知識點

一、延遲加載(Lazy Loading)

1. 核心定義

延遲加載是 MyBatis 對關(guān)聯(lián)查詢的優(yōu)化機制:查詢主對象時,不立即查詢其關(guān)聯(lián)對象(如用戶和賬戶的一對多關(guān)系),僅在實際使用關(guān)聯(lián)對象(調(diào)用 getter 方法)時,才觸發(fā)關(guān)聯(lián)查詢的 SQL 執(zhí)行。

2. 核心對比(延遲加載 vs 立即加載)

加載方式執(zhí)行時機適用場景優(yōu)點缺點
延遲加載調(diào)用關(guān)聯(lián)對象 getter 時關(guān)聯(lián)數(shù)據(jù)不常使用、關(guān)聯(lián)表數(shù)據(jù)量大減少無效查詢,提升性能可能觸發(fā) N+1 問題(循環(huán)查詢時)
立即加載查詢主對象時(如 LEFT JOIN 關(guān)聯(lián))關(guān)聯(lián)數(shù)據(jù)必用、數(shù)據(jù)量小一次查詢完成,避免多次數(shù)據(jù)庫交互冗余數(shù)據(jù)加載,性能損耗

3. 實現(xiàn)原理

基于 動態(tài)代理:查詢主對象時,MyBatis 返回主對象的代理實例;當(dāng)調(diào)用關(guān)聯(lián)對象的 getter 方法時,代理對象攔截該調(diào)用,觸發(fā)關(guān)聯(lián)查詢 SQL 執(zhí)行,查詢結(jié)果賦值后返回。

4. 配置要求(全局開啟)

需在 SqlMapConfig.xml 的 <settings> 標簽中配置(MyBatis 默認為關(guān)閉):

<settings>
    <!-- 全局開啟延遲加載(核心) -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 關(guān)閉積極加載(MyBatis 3.4.1+ 默認 false,低版本需手動設(shè)置)
         避免一次性加載所有關(guān)聯(lián)對象 -->
    <setting name="aggressiveLazyLoading" value="false"/>
    <!-- 可選:指定觸發(fā)延遲加載的方法(默認 equals/clone/hashCode/toString)
         調(diào)用這些方法不會觸發(fā)延遲加載 -->
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

5. 關(guān)聯(lián)查詢配置(XML 示例)

一對多(用戶 -> 賬戶)
<!-- UserMapper.xml -->
<resultMap id="userAccountMap" type="cn.tx.domain.User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <!-- collection 配置一對多關(guān)聯(lián),select 指定關(guān)聯(lián)查詢方法 -->
    <collection 
        property="accounts"       <!-- 主對象中關(guān)聯(lián)屬性名 -->
        ofType="cn.tx.domain.Account"  <!-- 關(guān)聯(lián)對象類型 -->
        column="id"              <!-- 關(guān)聯(lián)條件(主表主鍵 -> 從表外鍵) -->
        select="cn.tx.mapper.AccountMapper.findAccountsByUid"/>  <!-- 關(guān)聯(lián)查詢 SQL -->
</resultMap>
<!-- 主查詢:僅查詢用戶,不加載賬戶 -->
<select id="findUserById" resultMap="userAccountMap">
    SELECT id, username FROM user WHERE id = #{id}
</select>
一對一(用戶 -> 身份證)
<resultMap id="userIdCardMap" type="cn.tx.domain.User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <!-- association 配置一對一關(guān)聯(lián) -->
    <association 
        property="idCard" 
        javaType="cn.tx.domain.IdCard"  <!-- 一對一用 javaType -->
        column="id" 
        select="cn.tx.mapper.IdCardMapper.findByIdCardByUid"/>
</resultMap>

6. 關(guān)鍵注意事項

  • SqlSession 存活要求:延遲加載需通過 SqlSession 執(zhí)行關(guān)聯(lián)查詢,因此調(diào)用 getter 前,SqlSession 不能關(guān)閉(否則報 PersistenceException)。
  • N+1 問題規(guī)避:循環(huán)查詢多個主對象時,避免逐個觸發(fā)關(guān)聯(lián)查詢(1 次主查詢 + N 次關(guān)聯(lián)查詢);大量數(shù)據(jù)建議用 LEFT JOIN 立即加載。
  • 實體類無特殊要求:無需實現(xiàn)接口,僅需保證關(guān)聯(lián)屬性有 getter/setter 方法(代理對象需通過 getter 觸發(fā)加載)。

二、MyBatis 緩存機制(一級緩存 + 二級緩存)

MyBatis 緩存的核心目的是減少數(shù)據(jù)庫查詢次數(shù),提升性能,分為一級緩存(本地緩存)和二級緩存(全局緩存)。

1. 一級緩存(Local Cache)

(1)核心定義
  • 作用范圍:單個 SqlSession 內(nèi)部(會話級緩存),不同 SqlSession 互不共享。
  • 存儲介質(zhì):內(nèi)存(HashMap),默認開啟,無需額外配置。
(2)工作流程
  1. 同一 SqlSession 執(zhí)行相同查詢(相同 SQL + 參數(shù)):
    • 首次查詢:查數(shù)據(jù)庫,結(jié)果存入一級緩存。
    • 二次查詢:直接從緩存獲取,不執(zhí)行 SQL。
  2. 觸發(fā)緩存清空的場景:
    • 執(zhí)行 insert/update/delete 操作(自動清空當(dāng)前 SqlSession 的一級緩存,保證數(shù)據(jù)一致性)。
    • 調(diào)用 sqlSession.clearCache() 手動清空。
    • SqlSession 關(guān)閉(緩存失效)。
(3)配置說明

默認開啟,可通過 localCacheScope 調(diào)整作用域(全局配置):

<settings>
    <!-- SESSION(默認):緩存作用于整個 SqlSession -->
    <!-- STATEMENT:緩存僅作用于當(dāng)前 SQL 語句,執(zhí)行后立即清空 -->
    <setting name="localCacheScope" value="SESSION"/>
</settings>

2. 二級緩存(Second Level Cache)

(1)核心定義
  • 作用范圍:全局共享(跨 SqlSession),按 Mapper 接口(namespace)隔離(同一 namespace 共享緩存)。
  • 存儲介質(zhì):默認內(nèi)存(HashMap),可集成 Redis/Ehcache 等第三方緩存(持久化)。
  • 依賴要求:緩存的實體類必須實現(xiàn) Serializable 接口(緩存對象需序列化存儲)。
(2)工作流程
  1. 開啟二級緩存后,SqlSession 關(guān)閉時,一級緩存中的數(shù)據(jù)會寫入二級緩存。
  2. 新 SqlSession 執(zhí)行相同查詢(同一 namespace + 相同 SQL + 參數(shù)):
    • 先查二級緩存,命中則返回。
    • 未命中則查數(shù)據(jù)庫,結(jié)果存入一級緩存,SqlSession 關(guān)閉后同步到二級緩存。
  3. 觸發(fā)緩存清空的場景:
    • 同一 namespace 下執(zhí)行 insert/update/delete 操作(自動清空當(dāng)前 namespace 的二級緩存)。
    • 配置 flushInterval 自動刷新(如 60 秒)。
    • 手動調(diào)用 sqlSessionFactory.getConfiguration().getCache(namespace).clear()
(3)完整配置步驟

步驟 1:實體類實現(xiàn) Serializable

public class User implements Serializable { // 必須實現(xiàn),否則緩存序列化失敗
    private Integer id;
    private String username;
    private List<Account> accounts;
    // getter/setter/toString
}

步驟 2:全局開啟二級緩存(SqlMapConfig.xml)

<settings>
    <!-- 全局開啟二級緩存(默認 true,顯式配置更清晰) -->
    <setting name="cacheEnabled" value="true"/>
    <!-- 可選:全局緩存自動刷新時間(毫秒),默認不自動刷新 -->
    <setting name="cacheFlushInterval" value="60000"/>
</settings>

步驟 3:Mapper 開啟緩存(XML 方式)

在 Mapper XML 的 mapper 根標簽下添加 <cache> 標簽:

<!-- UserMapper.xml -->
<mapper namespace="cn.tx.mapper.UserMapper">
    <!-- 開啟當(dāng)前 namespace 的二級緩存 -->
    <cache 
        eviction="LRU"          <!-- 緩存回收策略(默認 LRU) -->
        flushInterval="60000"   <!-- 60 秒自動刷新 -->
        size="1024"             <!-- 緩存最大容量(默認 1024 個對象) -->
        readOnly="false"/>      <!-- false:可修改(返回副本);true:只讀(返回原對象,性能高) -->
    <!-- 查詢方法:默認 useCache="true"(啟用二級緩存) -->
    <select id="findUserById" resultMap="userAccountMap" useCache="true">
        SELECT id, username FROM user WHERE id = #{id}
    </select>
    <!-- 增刪改:默認 flushCache="true"(清空緩存),可省略 -->
    <update id="updateUser" flushCache="true">
        UPDATE user SET username = #{username} WHERE id = #{id}
    </update>
</mapper>

步驟 4:注解方式配置(備選)

// UserMapper.java(注解開啟二級緩存)
@CacheNamespace(
    implementation = PerpetualCache.class, // 緩存實現(xiàn)類(默認)
    eviction = LruCache.class,             // 回收策略
    flushInterval = 60000,
    size = 1024,
    readWrite = true // 等價于 readOnly="false"
)
public interface UserMapper {
    @Options(useCache = true) // 啟用二級緩存
    User findUserById(@Param("id") Integer id);
    @Options(flushCache = true) // 清空緩存
    void updateUser(User user);
}
(4)<cache>標簽核心屬性
屬性取值說明
eviction緩存回收策略(4 種):- LRU(默認):最近最少使用,移除最長時間未使用對象- FIFO:先進先出,按存入順序移除- SOFT:軟引用,內(nèi)存不足時移除- WEAK:弱引用,垃圾回收時移除
flushInterval自動刷新時間(毫秒),默認不自動刷新(僅增刪改觸發(fā))
size緩存最大對象數(shù)(默認 1024),需根據(jù)內(nèi)存調(diào)整
readOnlyfalse(默認):緩存對象可修改(返回序列化副本);true:只讀(返回原對象,性能更高)

3. 一二級緩存核心對比

特性一級緩存(Local Cache)二級緩存(Second Level Cache)
作用范圍單個 SqlSession全局(跨 SqlSession),按 namespace 隔離
開啟方式默認開啟,無需配置全局開關(guān) + Mapper 單獨開啟
存儲介質(zhì)內(nèi)存(HashMap)默認內(nèi)存,可集成第三方緩存
序列化要求實體類必須實現(xiàn) Serializable
數(shù)據(jù)一致性會話內(nèi)一致(自動清空)跨會話一致(增刪改自動清空)
適用場景單次會話內(nèi)重復(fù)查詢多會話共享數(shù)據(jù)(如字典、靜態(tài)數(shù)據(jù))

4. 緩存使用注意事項

  • 關(guān)聯(lián)查詢緩存一致性:如果 Mapper A 關(guān)聯(lián) Mapper B 的查詢,建議 Mapper B 也開啟二級緩存,避免關(guān)聯(lián)數(shù)據(jù)緩存不一致。
  • 禁用部分查詢緩存:實時性要求高的數(shù)據(jù)(如訂單狀態(tài)),可通過 useCache="false" 禁用二級緩存:
<select id="findRealTimeOrder" resultType="Order" useCache="false">
    SELECT * FROM order WHERE id = #{id}
</select>
  • 第三方緩存集成:生產(chǎn)環(huán)境建議用 Redis/Ehcache 替代默認內(nèi)存緩存(默認緩存重啟項目失效),需添加對應(yīng)依賴(如 mybatis-redis)并配置緩存實現(xiàn)類。
  • 避免緩存臟數(shù)據(jù):多表關(guān)聯(lián)查詢(跨 namespace)不建議用二級緩存,容易因某張表更新未觸發(fā)其他 namespace 緩存清空,導(dǎo)致臟數(shù)據(jù)。

三、延遲加載與緩存的協(xié)同工作

  1. 延遲加載的關(guān)聯(lián)查詢也會觸發(fā)緩存:首次調(diào)用 getter 執(zhí)行關(guān)聯(lián)查詢后,結(jié)果會存入一級緩存,SqlSession 關(guān)閉后同步到二級緩存。
  2. 緩存優(yōu)先級:二級緩存 > 一級緩存 > 數(shù)據(jù)庫(查詢時先查二級緩存,再查一級緩存,最后查數(shù)據(jù)庫)。
  3. 協(xié)同優(yōu)化場景:查詢主對象(如用戶)時用延遲加載(避免關(guān)聯(lián)數(shù)據(jù)冗余),主對象和關(guān)聯(lián)對象均開啟二級緩存(減少重復(fù)查詢),適合 “主數(shù)據(jù)不常變、關(guān)聯(lián)數(shù)據(jù)按需加載” 的場景(如用戶信息 + 歷史訂單)。

到此這篇關(guān)于mybatis中的延遲加載和一二級緩存深入解析的文章就介紹到這了,更多相關(guān)mybatis延遲加載和緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • "Method?Not?Allowed"405問題分析以及解決方法

    "Method?Not?Allowed"405問題分析以及解決方法

    項目中在提交表單時,提示“HTTP 405”錯誤——“Method Not Allowed”這里顯示的是,方法不被允許,下面這篇文章主要給大家介紹了關(guān)于"Method?Not?Allowed"405問題分析以及解決方法的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • 淺談SpringSecurity基本原理

    淺談SpringSecurity基本原理

    今天帶大家了解一下SpringSecurity的基本原理,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • SpringBoot基于Shiro處理ajax請求代碼實例

    SpringBoot基于Shiro處理ajax請求代碼實例

    這篇文章主要介紹了SpringBoot基于Shiro處理ajax請求代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • Java中String字符串轉(zhuǎn)具體對象的幾種常用方式

    Java中String字符串轉(zhuǎn)具體對象的幾種常用方式

    String對象可以用來存儲任何字符串類型的數(shù)據(jù),包括HTML、XML等格式的字符串,下面這篇文章主要給大家介紹了關(guān)于JavaString字符串轉(zhuǎn)具體對象的幾種常用方式,需要的朋友可以參考下
    2024-03-03
  • java捕獲異常信息存入txt文件示例

    java捕獲異常信息存入txt文件示例

    這篇文章主要介紹了java捕獲異常信息存入txt文件示例,需要的朋友可以參考下
    2014-04-04
  • 簡單介紹Java垃圾回收機制

    簡單介紹Java垃圾回收機制

    這篇文章主要介紹了簡單介紹Java垃圾回收機制,涉及一些相關(guān)的Java術(shù)語,Hotspot虛擬機,jvm體系結(jié)構(gòu)等內(nèi)容,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • mybatis-plugin插件執(zhí)行原理解析

    mybatis-plugin插件執(zhí)行原理解析

    這篇文章主要介紹了mybatis-plugin插件執(zhí)行原理,我們就需要來研究下Executor,ParameterHandler,ResultSetHandler,StatementHandler這4個對象的具體跟sql相關(guān)的方法,然后再進行修改,就可以直接起到aop的作用,需要的朋友可以參考下
    2022-10-10
  • 解決Springboot不能自動提交數(shù)據(jù)庫連接問題

    解決Springboot不能自動提交數(shù)據(jù)庫連接問題

    在使用SSM框架開發(fā)時,若在同一Service內(nèi)部方法間互相調(diào)用,直接使用this關(guān)鍵字會導(dǎo)致事務(wù)管理失效,從而引發(fā)如數(shù)據(jù)庫連接不足等問題,原因是通過this調(diào)用不會經(jīng)過Spring的代理,因此不會自動進行事務(wù)處理
    2024-09-09
  • java框架之maven是用來做什么的

    java框架之maven是用來做什么的

    這篇文章主要介紹了java之maven是用來做什么的,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Jackson多態(tài)序列化圖文詳解

    Jackson多態(tài)序列化圖文詳解

    jackson允許配置多態(tài)類型處理,當(dāng)進行反序列話時,JSON數(shù)據(jù)匹配的對象可能有多個子類型,為了正確的讀取對象的類型,我們需要添加一些類型信息,下面這篇文章主要給大家介紹了關(guān)于Jackson多態(tài)序列化的相關(guān)資料,需要的朋友可以參考下
    2022-06-06

最新評論

淮阳县| 武城县| 东阳市| 大安市| 吕梁市| 贵德县| 定襄县| 邵武市| 榆树市| 白银市| 克东县| 城口县| 汤阴县| 清流县| 姜堰市| 岑溪市| 东台市| 北碚区| 隆尧县| 五华县| 漳浦县| 连城县| 红安县| 红安县| 扬中市| 灵山县| 乌拉特中旗| 积石山| 土默特左旗| 库伦旗| 太谷县| 达日县| 开平市| 襄樊市| 遂平县| 萍乡市| 孟州市| 遵义县| 正阳县| 芦山县| 枣强县|