文章目录
- 前言
- 一、二级缓存
- 二、使用步骤
- 1.开启二级缓存
- 2.编写ApplicationContextHolder
- 3.编写RedisCache二级缓存工具类
- 4.在mapper.xml文件中开启全局二级缓存
- 5.配置RedisTemplate序列化工具类,实体也需要实现序列化接口
- 三、测试
- 总结
前言
本篇记录怎么使用Redis做Mybtais的缓存。
一、二级缓存
MyBatis中的缓存分为一级缓存和二级缓存
- 一级缓存:基于sqlSession的缓存
- 二级缓存:基于多个sqlSession 共享的namspace数据块
通常一个mapper 都一个namespace,所有的相关二级缓存都存在该namespace 数据块下
查询顺序:先去二级缓存,如果二级没有再去一级缓存,一级没有再去数据库
注意:在spring 配置的mybatis 中不存在一级缓存,二级缓存发生增删改,该namespace 下所有缓存数据 立即清空,目的是为了避免有脏数据存在
二、使用步骤
创建项目,导入依赖和基本编码部分不再赘述
1.开启二级缓存
在配置文件yml中加入以下配置

代码如下:
cache-enabled: true
2.编写ApplicationContextHolder
该类主要是为了在spring环境中获取非spring容器管理的bean
package com.lzl.secondcache;
import org.springframework.stereotype.Component;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextHolder.applicationContext = applicationContext;
}
public static RedisTemplate getRedisTemplate(){
return ApplicationContextHolder.applicationContext
.getBean("redisTemplate",RedisTemplate.class);
}
}
3.编写RedisCache二级缓存工具类
package com.lzl.secondcache;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class RedisCache implements Cache{
private RedisTemplate redisTemplate;
private String id;
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public RedisTemplate getRedisTemplate(){
if(redisTemplate == null){
synchronized (RedisCache.class){
if(redisTemplate == null){
RedisTemplate redisTemplate = ApplicationContextHolder.getRedisTemplate();
redisTemplate.setKeySerializer(RedisSerializer.string());
return redisTemplate;
}
return this.redisTemplate;
}
}
return redisTemplate;
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
public RedisCache(String id) {
System.out.println("id:"+id);
this.id = id;
}
@Override
public String getId() {
System.out.println("getId:"+id);
return id;
}
@Override
public void putObject(Object key, Object value) {
System.out.println("putObject中的key:"+key);
System.out.println("putObject中的value:"+value);
getRedisTemplate().opsForValue().set(key.toString(),value);
}
@Override
public Object getObject(Object key) {
System.out.println("getObject:"+key);
return getRedisTemplate().opsForValue().get(key.toString());
}
@Override
public Object removeObject(Object key) {
System.out.println("removeObject:"+key);
return getRedisTemplate().delete(key.toString());
}
@Override
public void clear() {
System.out.println("clear");
Set keys = getRedisTemplate().keys("*" + id + "*");
System.out.println("清空缓存keys:"+keys);
getRedisTemplate().delete(keys);
}
@Override
public int getSize() {
Set keys = getRedisTemplate().keys("*" + id + "*");
return keys.size();
}
}
4.在mapper.xml文件中开启全局二级缓存
<cache type="com.lzl.secondcache.RedisCache"/>
5.配置RedisTemplate序列化工具类,实体也需要实现序列化接口
package com.lzl.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
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;
/**
* --效率,是成功的核心关键--
*
* @Author lzl
* @Date 2023/3/9 08:05
*/
@Configuration
public class RedisConfig {
/**
* springboot 默认帮我们创建的RedisTemplate的key和value的序列化方式是jdk默认的方式,
* 我们有时候手动向redis中添加的数据可能无法被查询解析出来,所以我们需要修改序列化方式
* @param connectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 配置连接工厂
redisTemplate.setConnectionFactory(connectionFactory);
// 使用StringRedisSerializer来序列化和反序列化Redis的key值
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 使用Jackson2JsonRedisSerializer来序列化和反序列化Redis的value值
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
// 配置对象映射器
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围。ANY指包括private和public修饰符范围
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入类型,类的信息也将添加到json中,这样才可以根据类名反序列化。
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
// 将对象映射器添加到序列化器中
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 配置key,value,hashKey,hashValue的序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
return redisTemplate;
}
}
需要注意的是参数列表会报一个无法自动注入的错误,属于正常现象,不影响代码正常运行

实体类需要实现序列化接口如下图所示

三、测试
首先我们先开启Redis,这里开虚拟机太麻烦,我使用了windows版的redis


启动成功
启动项目

启动成功,测试二级缓存的基本思路是,先调用查询的方法,查看redis中是否有缓存数据,再调用删除的方法,再次查看查看redis中的缓存数据是否被删除
先执行查询

查看控制台

我这里之前已经查过一次,所以直接调用了缓存,没有执行sql语句,如果是第一次访问,会先执行sql语句,再建立缓存
执行删除

查看控制台

删除成功!我们再次执行查询

查看控制台:

发现执行了sql语句
再次查询

缓存命中!大功告成!
总结
本篇简单记录一下springboot整合mybatis使用redis做二级缓存