mybatisplus 配置二級緩存及實(shí)戰(zhàn)示例
MyBatis-Plus(簡稱 MP)作為 MyBatis 的增強(qiáng)工具,完全兼容 MyBatis 的二級緩存機(jī)制,同時提供了更便捷的配置方式。以下是基于 MyBatis-Plus 的二級緩存配置全指南,包含基礎(chǔ)配置、高級特性及實(shí)戰(zhàn)示例:
一、二級緩存核心依賴
確保項(xiàng)目中包含 MyBatis-Plus 及緩存相關(guān)依賴(以 Spring Boot 為例):
<!-- MyBatis-Plus核心依賴 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 可選:Redis緩存(分布式環(huán)境必備) -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-redis</artifactId>
<version>1.0.0-beta2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>二、基礎(chǔ)配置(本地緩存)
適用于單機(jī)環(huán)境,使用 MyBatis 默認(rèn)的內(nèi)存緩存(PerpetualCache)。
2.1 全局開啟二級緩存
在application.yml中開啟全局緩存開關(guān)(MyBatis 默認(rèn)開啟,建議顯式配置):
mybatis-plus:
configuration:
cache-enabled: true # 全局啟用二級緩存(默認(rèn)為true)
mapper-locations: classpath*:mapper/**/*.xml # 指定Mapper.xml路徑2.2 實(shí)體類實(shí)現(xiàn)序列化
二級緩存存儲對象需支持序列化(避免緩存失?。?/p>
package com.example.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
public class User implements Serializable {
private static final long serialVersionUID = 1L; // 必須添加序列化版本號
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String email;
private LocalDateTime createTime;
}2.3 在 Mapper 中開啟二級緩存
有兩種方式配置 Mapper 級別的二級緩存,根據(jù)項(xiàng)目風(fēng)格選擇:
方式 1:XML 配置(推薦,支持更多緩存參數(shù))
在對應(yīng)的UserMapper.xml中添加<cache>標(biāo)簽:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<!-- 配置二級緩存 -->
<cache
eviction="LRU" <!-- 緩存淘汰策略:LRU(最近最少使用) -->
flushInterval="60000" <!-- 自動刷新間隔(60秒) -->
size="1024" <!-- 最大緩存對象數(shù) -->
readOnly="false"/> <!-- 非只讀(需序列化) -->
<!-- MP自動生成的SQL會自動使用緩存,自定義SQL需顯式配置 -->
<select id="selectById" resultType="com.example.entity.User">
SELECT id, username, email, create_time AS createTime
FROM t_user WHERE id = #{id}
</select>
</mapper>方式 2:注解配置(簡化配置,適合無 XML 場景)
在 Mapper 接口上使用@CacheNamespace注解:
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.cache.impl.PerpetualCache;
// 注解方式開啟二級緩存,默認(rèn)使用PerpetualCache
@CacheNamespace(
eviction = LruCache.class, // 淘汰策略:LRU
flushInterval = 60000, // 刷新間隔60秒
size = 1024, // 最大緩存數(shù)
readWrite = true // 讀寫模式(非只讀)
)
public interface UserMapper extends BaseMapper<User> {
// 繼承BaseMapper的方法會自動使用緩存
}三、高級配置(分布式緩存,Redis 為例)
單機(jī)緩存無法滿足分布式環(huán)境需求,需集成 Redis 實(shí)現(xiàn)緩存共享。
3.1 配置 Redis 連接
創(chuàng)建redis.properties(src/main/resources/):
redis.host=localhost redis.port=6379 redis.timeout=2000 redis.password= # 無密碼則留空 redis.database=0 redis.default.expiration=1800000 # 緩存默認(rèn)過期時間(30分鐘)
3.2 配置 Mapper 使用 Redis 緩存
方式 1:XML 配置指定 Redis 緩存類型
<mapper namespace="com.example.mapper.UserMapper">
<!-- 使用Redis作為二級緩存 -->
<cache type="org.mybatis.caches.redis.RedisCache">
<property name="eviction" value="LRU"/>
<property name="flushInterval" value="60000"/>
<property name="size" value="1024"/>
</cache>
</mapper>方式 2:注解配置自定義 Redis 緩存
package com.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.CacheNamespace;
import org.mybatis.caches.redis.RedisCache;
// 注解方式指定Redis緩存
@CacheNamespace(implementation = RedisCache.class)
public interface UserMapper extends BaseMapper<User> {
}3.3 自定義 Redis 緩存(可選,優(yōu)化序列化)
默認(rèn) Redis 緩存使用 Java 序列化,性能較差,可自定義 JSON 序列化:
package com.example.cache;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.mybatis.caches.redis.RedisCache;
import java.util.concurrent.locks.ReadWriteLock;
public class JsonRedisCache extends RedisCache {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public JsonRedisCache(String id) {
super(id);
}
@Override
public void putObject(Object key, Object value) {
try {
// 序列化為JSON字符串
String jsonValue = OBJECT_MAPPER.writeValueAsString(value);
super.putObject(key, jsonValue);
} catch (Exception e) {
throw new RuntimeException("緩存序列化失敗", e);
}
}
@Override
public Object getObject(Object key) {
try {
String jsonValue = (String) super.getObject(key);
if (jsonValue != null) {
// 反序列化為目標(biāo)對象(根據(jù)實(shí)際類型調(diào)整)
return OBJECT_MAPPER.readValue(jsonValue, User.class);
}
} catch (Exception e) {
throw new RuntimeException("緩存反序列化失敗", e);
}
return null;
}
// 禁用默認(rèn)鎖(Redis本身是單線程,無需額外鎖)
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
}使用自定義緩存:
<cache type="com.example.cache.JsonRedisCache"/>
四、緩存細(xì)粒度控制
MyBatis-Plus 支持對單個方法配置緩存策略,覆蓋全局設(shè)置。
4.1 禁用特定查詢的緩存
<!-- XML方式:當(dāng)前查詢不使用二級緩存 -->
<select id="selectByUsername" resultType="User" useCache="false">
SELECT * FROM t_user WHERE username = #{username}
</select>
// 注解方式:使用@Options禁用緩存
import org.apache.ibatis.annotations.Options;
public interface UserMapper extends BaseMapper<User> {
@Options(useCache = false)
User selectByUsername(String username);
}4.2 強(qiáng)制刷新緩存
<!-- 執(zhí)行該查詢前清空緩存 -->
<select id="selectLatestUsers" resultType="User" flushCache="true">
SELECT * FROM t_user ORDER BY create_time DESC LIMIT 10
</select>
// 注解方式強(qiáng)制刷新
@Options(flushCache = Options.FlushCachePolicy.TRUE)
List<User> selectLatestUsers();五、驗(yàn)證二級緩存生效
編寫測試類驗(yàn)證緩存是否生效:
package com.example.test;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Objects;
@Slf4j
@SpringBootTest
public class MpCacheTest {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Test
public void testSecondLevelCache() {
// 第一次查詢:緩存未命中,查數(shù)據(jù)庫
try (SqlSession session1 = sqlSessionFactory.openSession()) {
UserMapper mapper1 = session1.getMapper(UserMapper.class);
User user1 = mapper1.selectOne(new QueryWrapper<User>().eq("id", 1L));
log.info("第一次查詢結(jié)果:{}", user1);
} // 會話關(guān)閉,數(shù)據(jù)存入二級緩存
// 第二次查詢:命中二級緩存
try (SqlSession session2 = sqlSessionFactory.openSession()) {
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.selectOne(new QueryWrapper<User>().eq("id", 1L));
log.info("第二次查詢結(jié)果:{}", user2);
}
}
}預(yù)期日志(第二次查詢無 SQL 輸出,證明命中緩存):
第一次查詢結(jié)果:User(id=1, username=test, ...) ==> Preparing: SELECT ... FROM t_user WHERE (id = ?) ==> Parameters: 1(Long) <== Total: 1 第二次查詢結(jié)果:User(id=1, username=test, ...) // 無SQL執(zhí)行,命中二級緩存
六、注意事項(xiàng)
- BaseMapper 方法的緩存行為:
- MyBatis-Plus 自動生成的 CRUD 方法(如
selectById、updateById)會自動遵循緩存配置,更新操作會觸發(fā)緩存清空。
- MyBatis-Plus 自動生成的 CRUD 方法(如
- 分頁插件與緩存:
- 使用
Page分頁查詢時,緩存鍵會包含分頁參數(shù)(pageNum、pageSize),確保不同分頁的結(jié)果正確緩存。
- 使用
- 多表關(guān)聯(lián)查詢:
- 若 Mapper 中包含多表關(guān)聯(lián)查詢,建議使用
@CacheNamespaceRef關(guān)聯(lián)相關(guān) Mapper,確保更新任一表時同步清空緩存:
- 若 Mapper 中包含多表關(guān)聯(lián)查詢,建議使用
@CacheNamespaceRef(UserMapper.class) // 共享UserMapper的緩存
public interface UserOrderMapper extends BaseMapper<UserOrder> {
}- 避免緩存超大結(jié)果集:
- 對返回大量數(shù)據(jù)的查詢(如
selectList()無限制條件),建議禁用緩存(useCache=false),避免內(nèi)存溢出。
- 對返回大量數(shù)據(jù)的查詢(如
總結(jié)
MyBatis-Plus 配置二級緩存的核心是:
- 全局開啟
cache-enabled: true - 實(shí)體類實(shí)現(xiàn)
Serializable - 在 Mapper 中通過 XML 或注解配置
<cache>/@CacheNamespace - 分布式環(huán)境替換為 Redis 緩存
通過合理配置,可充分利用二級緩存減少數(shù)據(jù)庫訪問,同時需平衡緩存命中率與數(shù)據(jù)一致性,避免臟讀問題。
到此這篇關(guān)于mybatisplus 配置二級緩存的文章就介紹到這了,更多相關(guān)mybatisplus 二級緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java selenium截圖操作的實(shí)現(xiàn)
這篇文章主要介紹了Java selenium截圖操作的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
SpringBoot項(xiàng)目啟動時預(yù)加載操作方法
Spring Boot是一種流行的Java開發(fā)框架,它提供了許多方便的功能來簡化應(yīng)用程序的開發(fā)和部署,這篇文章主要介紹了SpringBoot項(xiàng)目啟動時預(yù)加載,需要的朋友可以參考下2023-09-09
mybatis中resultMap 標(biāo)簽的使用教程
resultMap 標(biāo)簽用來描述如何從數(shù)據(jù)庫結(jié)果集中來加載對象,這篇文章重點(diǎn)給大家介紹mybatis中resultMap 標(biāo)簽的使用,感興趣的朋友一起看看吧2018-07-07
Java異常的幾個謎題_動力節(jié)點(diǎn)Java學(xué)院整理
本文給大家收藏整理java異常的幾個謎題,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-06-06
最流行的java后臺框架spring quartz定時任務(wù)
近日項(xiàng)目開發(fā)中需要執(zhí)行一些定時任務(wù),比如需要在每天凌晨時候,分析一次前一天的日志信息,借此機(jī)會整理了一下定時任務(wù)的幾種實(shí)現(xiàn)方式,由于項(xiàng)目采用spring框架,所以我都將結(jié)合spring框架來介紹2015-12-12
rabbitmq結(jié)合spring實(shí)現(xiàn)消息隊(duì)列優(yōu)先級的方法
本篇文章主要介紹了rabbitmq結(jié)合spring實(shí)現(xiàn)消息隊(duì)列優(yōu)先級的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02
Java中出現(xiàn)InterruptedException異常的原因及解決方案
在Java多線程編程中,InterruptedException是一個常見但又容易被忽視的異常,它通常出現(xiàn)在線程被外部中斷時,例如調(diào)用Thread.interrupt() 或線程池關(guān)閉時,本文將通過一個實(shí)際的日志案例,分析InterruptedException 的產(chǎn)生原因、影響,需要的朋友可以參考下2025-06-06

