<cache type=""/>标签中type属性是指定了一个类,这个类是Mybatis的cache接口给我们提供的实现类,该接口类下有很多是实现,而mybatis中默认用的类是PerpetualCache类

可以看到它实现mybatis的Cache接口,底层定义的是键和值都是Object的HashMap,要想使用Redis分布式缓存,就得把底层的HashMap实现改成Redis实现。因此要想做Redis分布式缓存,就得自己写一个Redis**Cache去继承Cache接口
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.apache.ibatis.cache.impl;
import java.util.HashMap;
import java.util.Map;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;
public class PerpetualCache implements Cache {
private final String id;
private final Map<Object, Object> cache = new HashMap();
public PerpetualCache(String id) {
this.id = id;
}
public String getId() {
return this.id;
}
public int getSize() {
return this.cache.size();
}
public void putObject(Object key, Object value) {
this.cache.put(key, value);
}
public Object getObject(Object key) {
return this.cache.get(key);
}
public Object removeObject(Object key) {
return this.cache.remove(key);
}
public void clear() {
this.cache.clear();
}
public boolean equals(Object o) {
if (this.getId() == null) {
throw new CacheException("Cache instances require an ID.");
} else if (this == o) {
return true;
} else if (!(o instanceof Cache)) {
return false;
} else {
Cache otherCache = (Cache)o;
return this.getId().equals(otherCache.getId());
}
}
public int hashCode() {
if (this.getId() == null) {
throw new CacheException("Cache instances require an ID.");
} else {
return this.getId().hashCode();
}
}
}

putObject上打上断点,执行测试程序,put完之后发现cache的size = 1了,key和value的值也都可以查看到。
在测试程序,写了两次查询,那么下一次查询应该是GetObject,它将根据拥有的key,拿到对应的信息。

结论:mybatis底层默认使用的是 org.apache.ibatis.cache.impl.PerpetualCache 实现。也就是
<cache type="org.apache.ibatis.cache.impl.PerpetualCache"/>
要想使用Redis,需要自定义RedisCache实现
1.通过mybatis默认cache源码得知 可以使用自定义Cache类 implements Cache 接口 并对里面的方法进行实现
2.使用RedisCache实现,type里换成自己定义的
<cache type="****.RedisCache"/>
package com.wang.cache;
import com.baizhi.util.ApplicationContextUtils;
import org.apache.ibatis.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.DigestUtils;
import java.util.concurrent.TimeUnit;
//自定义Redis缓存实现
public class RedisCache implements Cache {
//当前放入缓存的mapper的namespace
private final String id;
//必须存在构造方法
public RedisCache(String id) {
System.out.println("id:=====================> " + id);
this.id = id;
}
//返回cache唯一标识
@Override
public String getId() {
return this.id;
}
//缓存放入值 redis RedisTemplate StringRedisTemplate
@Override
public void putObject(Object key, Object value) {
//key大体上是id+方法名(比如是findAll)+一串数字+sql语句
System.out.println("key:" + key.toString());
System.out.println("value:" + value);
//使用redishash类型作为缓存存储模型 key hashkey value
getRedisTemplate().opsForHash().put(id.toString(),getKeyToMD5(key.toString()),value);
if(id.equals("com.wang.dao.UserDAO")){
//缓存超时 client 用户 client 员工
getRedisTemplate().expire(id.toString(),1, TimeUnit.HOURS);
}
if(id.equals("com.wang.dao.CityDAO")){
//缓存超时 client 用户 client 员工
getRedisTemplate().expire(id.toString(),30, TimeUnit.MINUTES);
}
//.....指定不同业务模块设置不同缓存超时时间
}
//获取中获取数据
@Override
public Object getObject(Object key) {
System.out.println("key:" + key.toString());
return getRedisTemplate().opsForHash().get(id.toString(), getKeyToMD5(key.toString()));
}
//注意:这个方法为mybatis保留方法 默认没有实现 后续版本可能会实现
@Override
public Object removeObject(Object key) {
System.out.println("根据指定key删除缓存");
return null;
}
@Override
public void clear() {
System.out.println("清空缓存~~~");
//清空namespace
getRedisTemplate().delete(id.toString());//清空缓存
}
//用来计算缓存数量
@Override
public int getSize() {
//获取hash中key value数量
return getRedisTemplate().opsForHash().size(id.toString()).intValue();
}
//封装redisTemplate
private RedisTemplate getRedisTemplate(){
//通过application工具类获取redisTemplate
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
//进行序列化操作
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
//封装一个对key进行md5处理方法
private String getKeyToMD5(String key){
return DigestUtils.md5DigestAsHex(key.getBytes());
}
}
构造函数的参数String id 就是你mapper.xml的namespace。
比如在我的UserDAOMapper.xml中
<mapper namespace="com.wang.dao.UserDAO">
那么id就是com.wang.dao.UserDAO
在继承Cache并生成重写方法后,必须要有一个构造方法以及getId返回值不能为空。

注意: 只要发生增删改操作,mybatis默认都是调用函数clear清空缓存。
如何获取RedisTemplate?
由于RedisCache这个类不是工厂管理,而是由mybatis实例化的,因此我们的RedisTemplate无法通过注入的方式进行获取。通过ApplicationContext context.getbean(“redisTemplate”) 进行获取。
package com.wang.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
//用来获取springboot创建好的工厂
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
//保留下来工厂
private static ApplicationContext applicationContext;
//将创建好工厂以参数形式传递给这个类
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//提供在工厂中获取对象的方法 //RedisTemplate redisTemplate
public static Object getBean(String beanName){
return applicationContext.getBean(beanName);
}
}
1391

被折叠的 条评论
为什么被折叠?



