package com.wbb.cache; import com.wbb.util.ApplicationContextUtils; import org.apache.ibatis.cache.Cache; 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) { System.out.println("key:" + key.toString()); System.out.println("value:" + value); // //通过application工具类获取redisTemplate // RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate"); // redisTemplate.setKeySerializer(new StringRedisSerializer()); // redisTemplate.setHashKeySerializer(new StringRedisSerializer()); //使用redishash类型作为缓存存储模型 key hashkey value getRedisTemplate().opsForHash().put(id.toString(),getKeyToMD5(key.toString()),value); if(id.equals("com.baizhi.dao.UserDAO")){ //缓存超时 client 用户 client 员工 getRedisTemplate().expire(id.toString(),1, TimeUnit.HOURS); } if(id.equals("com.baizhi.dao.CityDAO")){ //缓存超时 client 用户 client 员工 getRedisTemplate().expire(id.toString(),30, TimeUnit.MINUTES); } //.....指定不同业务模块设置不同缓存超时时间 } //获取中获取数据 @Override public Object getObject(Object key) { System.out.println("key:" + key.toString()); // //通过application工具类获取redisTemplate // RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate"); // redisTemplate.setKeySerializer(new StringRedisSerializer()); // redisTemplate.setHashKeySerializer(new StringRedisSerializer()); //根据key 从redis的hash类型中获取数据 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()); } }
package com.wbb.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); } }
在xml中开启缓存标签
<!--开启mybatis二级缓存--> <cache type="com.wbb.cache.RedisCache"/>
如果都是单表操作,上面写的没问题,如果是关联查询的话,就有问题,例如:
查询用户 和用户的 job list
在userdao查的,此时 redis里面就存了userdao 的 findUser的key
如果此时修改了用户的job list,因为用户job也是 另一个dao jobdao里面写的,此时更新的时候并不会更新userdao的redis,就出现了数据错误
使用
<cache-ref namespace="com.wbb.userDao"> 让 jobdao 关联到 userdao
就相当于 jobdao 存的redis 的 大key 是 userdao了,而不是 他自己,此时不生成 jobdao 的redis 大key ,都存在userdao里
此为视频学习笔记