创建项目
第一步当然是创建一个springBoot项目,并导入依赖嘛。这就不多说了。
这儿我们就不用jedis了,spring对redis也有支持,我们就用spring-boot-starter-data-redis来整合redis。
org.springframework.boot
spring-boot-starter-data-redis
2.3.5.RELEASE
写配置
spring:
#redis 的配置
redis:
host: localhost
port: 6379
database: 0
# 数据源,我用了druid
datasource:
type: com.alibaba.druid.pool.DruidDataSource
password: 12345678
username: root
url: jdbc:mysql://localhost:3306/redis?characterEncoding=UTF-8
druid:
stat-view-servlet:
url-pattern: /druid/*
login-password: 123456
login-username: admin
#mybatis 的配置
mybatis:
mapper-locations: classpath:/mapper/*.xml
# 配置日志打印
logging:
level:
com.tao.redis_demo_springboot.dao: debug
## 环境
我们来搭建基本的一个增删该查
那我们该如何让redis进行缓存呢?
在mybatis中,我们可以通过cache标签来开启二级缓存,这个默认的缓存是org.apache.ibatis.cache.impl.PerpetualCache
来实现的。
在cache标签中,type可以指定缓存类。那我们可以自定义一个缓存类,用springboot提供的redistemplate 来对redis进行操作。也就是说,我们通过这个自定义的缓存类来操作redis,我们也就成功地用redis来做缓存了。
自定义缓存类
那我们如何来定义一个缓存类呢?
我们可以看看mybatis他是如何实现的,我们可以照猫画虎,去看看PerpetualCache
的源码。
public class PerpetualCache implements Cache {
private final String id;
private final Map
一看源码就很清晰了,他是用一个map来管理缓存。那可以把缓存在redis中也写成一个map的格式。
那么我们可以来编写一个自己定义的缓存类,来实现Cache接口。
在这之前,我们需要考虑如何在这个缓存类中拿到RedisTemplate呢?我们可以写一个工具类,继承于ApplicationContextAware类,这样我们可以通过这个类来拿到spring中的redisTemplate。
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext Context) throws BeansException {
applicationContext = Context;
}
public Object getBean(String beanName){
Object bean = applicationContext.getBean(beanName);
return bean;
}
}
接下来我们在自定义的缓存类中就可以拿到redisTemplate了并实现Cache中的方法。
public class RedisCache implements Cache {
private final String id ;
public RedisCache(String id) {
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public void putObject(Object o, Object o1) {
getRedisTemplate().opsForHash().put(id.toString(),o.toString(),o1);
}
@Override
public Object getObject(Object o) {
return getRedisTemplate().opsForHash().get(id.toString(), o.toString());
}
@Override
public Object removeObject(Object o) {
return null;
}
@Override
public void clear() {
getRedisTemplate().delete(id.toString());
}
@Override
public int getSize() {
int size = Math.toIntExact(getRedisTemplate().opsForHash().size(id.toString()));
return size;
}
private RedisTemplate getRedisTemplate(){
ApplicationContextUtil applicationContextUtil = new ApplicationContextUtil();
RedisTemplate redisTemplate = (RedisTemplate) applicationContextUtil.getBean("redisTemplate");
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
然后我们在mybatis中的mapper 的xml中添加上cache标签,并把type设置为我们自定义的缓存类。这时候我们的redis中就会存在我们查询过的结果了。
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
说一下这个的作用,我们都知道,在redis中的hash中是key1 和 一个hash,hash中是一个key2 和 value 。setKeySerializer是为了避免序列化key,setHashKeySerializer是为了避免序列化key2.
z
可以看到在redis中,可读性更高了。
其他
优化:我们可以将那么一大串的key缩短,例如使用md5算法,将key统一地变为32位的16进制数字。
mybatis中的二级缓存会在进行写操作的时候,会将该mapper中的缓存清空。但是,,我们考虑一下,如果是多表更新呢,在A mapper中的更新语句中更新了B的某个记录的值,那么,B的缓存中没有做对应的修改,这样就会导致脏读,督导一个错误的数据。为了解决这个问题,可以将cache标签中的改为cache-ref,将这个缓存指向关联表的mapper。
例如:在A的mapper
而B的mapper 为