mybatisplus 配置二级缓存及实战示例
作者:一叶飘零_sweeeet
MyBatis-Plus(简称 MP)作为 MyBatis 的增强工具,完全兼容 MyBatis 的二级缓存机制,同时提供了更便捷的配置方式。以下是基于 MyBatis-Plus 的二级缓存配置全指南,包含基础配置、高级特性及实战示例:
一、二级缓存核心依赖
确保项目中包含 MyBatis-Plus 及缓存相关依赖(以 Spring Boot 为例):
<!-- MyBatis-Plus核心依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 可选:Redis缓存(分布式环境必备) -->
<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>二、基础配置(本地缓存)
适用于单机环境,使用 MyBatis 默认的内存缓存(PerpetualCache)。
2.1 全局开启二级缓存
在application.yml中开启全局缓存开关(MyBatis 默认开启,建议显式配置):
mybatis-plus:
configuration:
cache-enabled: true # 全局启用二级缓存(默认为true)
mapper-locations: classpath*:mapper/**/*.xml # 指定Mapper.xml路径2.2 实体类实现序列化
二级缓存存储对象需支持序列化(避免缓存失败):
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 级别的二级缓存,根据项目风格选择:
方式 1:XML 配置(推荐,支持更多缓存参数)
在对应的UserMapper.xml中添加<cache>标签:
<?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" <!-- 最大缓存对象数 -->
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;
// 注解方式开启二级缓存,默认使用PerpetualCache
@CacheNamespace(
eviction = LruCache.class, // 淘汰策略:LRU
flushInterval = 60000, // 刷新间隔60秒
size = 1024, // 最大缓存数
readWrite = true // 读写模式(非只读)
)
public interface UserMapper extends BaseMapper<User> {
// 继承BaseMapper的方法会自动使用缓存
}三、高级配置(分布式缓存,Redis 为例)
单机缓存无法满足分布式环境需求,需集成 Redis 实现缓存共享。
3.1 配置 Redis 连接
创建redis.properties(src/main/resources/):
redis.host=localhost redis.port=6379 redis.timeout=2000 redis.password= # 无密码则留空 redis.database=0 redis.default.expiration=1800000 # 缓存默认过期时间(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 缓存(可选,优化序列化)
默认 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) {
// 反序列化为目标对象(根据实际类型调整)
return OBJECT_MAPPER.readValue(jsonValue, User.class);
}
} catch (Exception e) {
throw new RuntimeException("缓存反序列化失败", e);
}
return null;
}
// 禁用默认锁(Redis本身是单线程,无需额外锁)
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
}使用自定义缓存:
<cache type="com.example.cache.JsonRedisCache"/>
四、缓存细粒度控制
MyBatis-Plus 支持对单个方法配置缓存策略,覆盖全局设置。
4.1 禁用特定查询的缓存
<!-- XML方式:当前查询不使用二级缓存 -->
<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 强制刷新缓存
<!-- 执行该查询前清空缓存 -->
<select id="selectLatestUsers" resultType="User" flushCache="true">
SELECT * FROM t_user ORDER BY create_time DESC LIMIT 10
</select>
// 注解方式强制刷新
@Options(flushCache = Options.FlushCachePolicy.TRUE)
List<User> selectLatestUsers();五、验证二级缓存生效
编写测试类验证缓存是否生效:
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() {
// 第一次查询:缓存未命中,查数据库
try (SqlSession session1 = sqlSessionFactory.openSession()) {
UserMapper mapper1 = session1.getMapper(UserMapper.class);
User user1 = mapper1.selectOne(new QueryWrapper<User>().eq("id", 1L));
log.info("第一次查询结果:{}", user1);
} // 会话关闭,数据存入二级缓存
// 第二次查询:命中二级缓存
try (SqlSession session2 = sqlSessionFactory.openSession()) {
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.selectOne(new QueryWrapper<User>().eq("id", 1L));
log.info("第二次查询结果:{}", user2);
}
}
}预期日志(第二次查询无 SQL 输出,证明命中缓存):
第一次查询结果:User(id=1, username=test, ...) ==> Preparing: SELECT ... FROM t_user WHERE (id = ?) ==> Parameters: 1(Long) <== Total: 1 第二次查询结果:User(id=1, username=test, ...) // 无SQL执行,命中二级缓存
六、注意事项
- BaseMapper 方法的缓存行为:
- MyBatis-Plus 自动生成的 CRUD 方法(如
selectById、updateById)会自动遵循缓存配置,更新操作会触发缓存清空。
- MyBatis-Plus 自动生成的 CRUD 方法(如
- 分页插件与缓存:
- 使用
Page分页查询时,缓存键会包含分页参数(pageNum、pageSize),确保不同分页的结果正确缓存。
- 使用
- 多表关联查询:
- 若 Mapper 中包含多表关联查询,建议使用
@CacheNamespaceRef关联相关 Mapper,确保更新任一表时同步清空缓存:
- 若 Mapper 中包含多表关联查询,建议使用
@CacheNamespaceRef(UserMapper.class) // 共享UserMapper的缓存
public interface UserOrderMapper extends BaseMapper<UserOrder> {
}- 避免缓存超大结果集:
- 对返回大量数据的查询(如
selectList()无限制条件),建议禁用缓存(useCache=false),避免内存溢出。
- 对返回大量数据的查询(如
总结
MyBatis-Plus 配置二级缓存的核心是:
- 全局开启
cache-enabled: true - 实体类实现
Serializable - 在 Mapper 中通过 XML 或注解配置
<cache>/@CacheNamespace - 分布式环境替换为 Redis 缓存
通过合理配置,可充分利用二级缓存减少数据库访问,同时需平衡缓存命中率与数据一致性,避免脏读问题。
到此这篇关于mybatisplus 配置二级缓存的文章就介绍到这了,更多相关mybatisplus 二级缓存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
