一、Redis作为二级缓存
Mybatis的二级缓存可以自动地对数据库的查询做缓存,并且可以在更新数据时同时自动地更新缓存。
实现Mybatis的二级缓存很简单,只需要新建一个类实现org.apache.ibatis.cache.Cache接口即可。
该接口共有以下五个方法:
方法 | |
---|---|
String getId() | mybatis缓存操作对象的标识符。一个mapper对应一个mybatis的缓存操作对象 |
void putObject(Object key, Object value) | 将查询结果存入缓存 |
Object getObject(Object key) | 从缓存中获取被缓存的查询结果 |
Object removeObject(Object key) | 从缓存中删除对应的key、value。只有在回滚时触发。一般我们也可以不用实现 |
void clear() | 发生更新时,清除缓存。 |
int getSize() | 可选实现。返回缓存的数量。 |
ReadWriteLock getReadWriteLock() | 可选实现。用于实现原子性的缓存操作 |
二、实现Cache接口:
public class RedisCache implements Cache {
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final String id;
private RedisTemplate redisTemplate;
//redis过期时间
private static final long EXPIRE_TIME_IN_MINUTES = 30;
public RedisCache(String id){
if (id == null){
throw new IllegalArgumentException("Cache instance required an ID");
}
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public void putObject(Object key, Object value) {
RedisTemplate redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
opsForValue.set(key.toString(),value,EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);
}
@Override
public Object getObject(Object key) {
RedisTemplate redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
return opsForValue.get(key.toString());
}
@Override
public Object removeObject(Object key) {
RedisTemplate redisTemplate = getRedisTemplate();
redisTemplate.delete(key);
return null;
}
@Override
public void clear() {
RedisTemplate redisTemplate = getRedisTemplate();
redisTemplate.execute((RedisCallback) connection -> {
connection.flushDb();
return null;
});
}
@Override
public int getSize() {
Long size = (Long) redisTemplate.execute((RedisCallback) connection -> connection.dbSize());
return size.intValue();
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
private RedisTemplate getRedisTemplate() {
if(redisTemplate == null){
redisTemplate = ApplicationContextHolder.getBean("redisTemplate");
}
return redisTemplate;
}
}
ApplicationContextHolder
@Component
public class ApplicationContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextHolder.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
checkApplicationContext();
return applicationContext;
}
public static <T> T getBean(String name){
checkApplicationContext();
return (T) applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> clazz){
checkApplicationContext();
return (T) applicationContext.getBeansOfType(clazz);
}
public static void cleanApplicationContext(){
applicationContext = null;
}
private static void checkApplicationContext(){
if(applicationContext ==null){
if (applicationContext == null){
throw new IllegalStateException("applicationContext未注入,请在applicationContext.xml中定义SpringContext");
}
}
}
@Override
public void destroy() throws Exception {
}
}
关键点:
- 自己实现的二级缓存,必须要有一个带id的构造函数,否则会报错。
- 我们使用Spring封装的redisTemplate来操作Redis
- 我们采用的redis序列化方式是默认的jdk序列化。所以数据库的查询对象需要实现Serializable接口。
三、开启二级缓存
接下来,我们需要在Mapper.xml中开启二级缓存:
<?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="">
<!-- 开启基于redis的二级缓存 -->
<cache type="com.xxx.MybatisRedisCache"/>
</mapper>
标签属性说明
-
eviction:定义缓存移除机制(算法),默认为LRU(最近最少使用),它会清除最少使用的数据,还有一种FIFO(先进先出),它会清除最先进来的数据。
-
flushInterval:定义缓存刷新周期,单位为毫秒。
-
size:标识缓存cache中容纳的最大元素,默认为1024。
-
readOnly:默认为false,可配置为true缓存只读。
对于有不需要用到二级缓存的语句可以在标签内写userCache="false",默认为true开启缓存。
<select id="get" ... useCache="false">
</select>
<insert | update | delete id="" ... flushCache="false">
</select>
要点
- select 默认useCache为true:使用缓存,flushCache为false:不清空缓存
- insert、update、delete 默认flushCache为true:清空缓存
网友评论