发布于2026-07-10 阅读(0)
扫一扫,手机访问
在 MyBatis-Plus 中接入 Redis 作为二级缓存,关键其实就两个点:一是把 RedisTemplate 的序列化方式配对,二是搞定 MyBatis 的 Cache 接口实现。这里有个小坑要注意——MyBatis 的 Cache 实现类不受 Spring 容器直接管理,所以得想个办法让它可以拿到 RedisTemplate。

下面直接上配置和代码,一步步说清楚。
先把 MyBatis-Plus 和 Spring Data Redis 的依赖加进来:
com.baomidou mybatis-plus-boot-starter 3.5.3.1 org.springframework.boot spring-boot-starter-data-redis cn.hutool hutool-all 5.8.22
MyBatis 缓存的对象必须可序列化,这里推荐用 JSON 序列化,比如 Jackson。相比 JDK 默认序列化,JSON 更节省空间,可读性也更好。
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// 使用 String 序列化 Key
StringRedisSerializer stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
template.setHashKeySerializer(stringSerializer);
// 使用 Jackson 序列化 Value
Jackson2JsonRedisSerializer
接下来写一个自定义类,实现 org.apache.ibatis.cache.Cache 接口。注意,这个类是由 MyBatis 创建的,不是 Spring,所以不能直接用 @Autowired,得通过 ApplicationContext 拿到 RedisTemplate。
方案 A:使用 Hutool 的 SpringUtil(推荐,代码更简洁)
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@Slf4j
public class MybatisRedisCache implements Cache {
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final String id;
private RedisTemplate redisTemplate;
// 缓存过期时间(分钟),可根据业务调整
private static final long EXPIRE_TIME_IN_MINUTES = 30;
public MybatisRedisCache(String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public void putObject(Object key, Object value) {
getRedisTemplate().opsForHash().put(getId(), key.toString(), value);
log.debug("Put query result to redis: key={}", key);
}
@Override
public Object getObject(Object key) {
log.debug("Get cached query result from redis: key={}", key);
return getRedisTemplate().opsForHash().get(getId(), key.toString());
}
@Override
public Object removeObject(Object key) {
log.debug("Remove cached query result from redis: key={}", key);
return getRedisTemplate().opsForHash().delete(getId(), key.toString());
}
@Override
public void clear() {
log.debug("Clear all cached query results from redis for namespace: {}", getId());
getRedisTemplate().delete(getId());
}
@Override
public int getSize() {
Long size = getRedisTemplate().opsForHash().size(getId());
return size == null ? 0 : size.intValue();
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
private RedisTemplate getRedisTemplate() {
if (redisTemplate == null) {
// 从 Spring 容器中获取 RedisTemplate
redisTemplate = SpringUtil.getBean("redisTemplate");
}
return redisTemplate;
}
}
方案 B:使用静态 ApplicationContext 持有者(如果不使用 Hutool)
如果不依赖 Hutool,那就写一个 SpringContextHolder 类,实现 ApplicationContextAware 接口来静态持有 Bean。然后在 MybatisRedisCache 中调用 SpringContextHolder.getBean("redisTemplate") 即可。
mybatis-plus:
configuration:
cache-enabled: true # 全局开启二级缓存
# 其他配置...
在具体的 Mapper 接口或 XML 中指定使用刚才写的 Redis 缓存。
方式一:注解方式(推荐)
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.CacheNamespace; @CacheNamespace(implementation = MybatisRedisCache.class) public interface UserMapper extends BaseMapper{ // 查询方法 }
方式二:XML 方式
在对应的 UserMapper.xml 里加这么一段:
User)必须实现 Serializable 接口,不然 JSON 序列化可能会翻车。insert/update/delete 操作后会清空该 Namespace 下的所有缓存。在分布式高并发场景下,这种行为可能不够精细。如果业务对缓存一致性要求高,可以考虑在服务层用 Spring Cache(比如 @Cacheable)来替代 MyBatis 二级缓存,拿到的控制粒度会更细。opsForHash,把同一个 Mapper Namespace 下的缓存项都放在一个 Hash 里,Key 是查询条件的哈希或字符串。这样做方便管理和清理特定 Mapper 的缓存。cache-enabled: true 已经配好,这是关键。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8