From 9f3039776ec6ea59b0723d1f8f565debd6172786 Mon Sep 17 00:00:00 2001 From: zicheng <523186180@qq.com> Date: Mon, 10 Aug 2020 10:01:55 +0800 Subject: [PATCH] 完善mybatis的二级缓存 --- src/main/java/com/sunyo/wlpt/message/bus/service/cache/RedisCache.java | 49 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/sunyo/wlpt/message/bus/service/cache/RedisCache.java b/src/main/java/com/sunyo/wlpt/message/bus/service/cache/RedisCache.java index b761984..56ea978 100644 --- a/src/main/java/com/sunyo/wlpt/message/bus/service/cache/RedisCache.java +++ b/src/main/java/com/sunyo/wlpt/message/bus/service/cache/RedisCache.java @@ -15,6 +15,16 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author 子诚 * Description:自定义Redis作为mybatis二级缓存实现 + * 问题描述:缓存穿透、缓存雪崩 + * <p> + * 缓存穿透:就是说利用一些列措施,使得访问避开了缓存,直接访问数据库,使得数据库不堪重负引起的问题。比如(压测)访问数据库中不存在的数据 + * 解决方案:读取数据库,不存在;依旧生成对应的key,放到缓存中,但是对应的value是null(mybatis的二级缓存是这样解决的)。 + * 下次再次访问的话,就是读取缓存。 + * <p> + * 缓存雪崩:是指在某一特殊时刻,缓存中的缓存全部失效,然后这一时刻又有大量的数据库访问,导致数据库不堪重负。 + * 解决方案:根据业务的不同设置不同的缓存失效时间。 + * 比如:这个项目,做了3个namespace的缓存,其中一个namespace,共有5个Mapper指向它。所以选择使用范围内的随机值,来做缓存失效时间 + * <p> * 时间:2020/8/6 9:37 */ public class RedisCache implements Cache { @@ -30,11 +40,6 @@ public class RedisCache implements Cache { private static final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); /** - * 缓存对象的是失效时间,30分钟 - */ - private static final long CACHE_TIME_IN_MINT = 30; - - /** * 当前放入缓存的mapper的namespace */ private final String id; @@ -67,8 +72,34 @@ public class RedisCache implements Cache { { RedisTemplate redisTemplate = getRedisTemplate(); // 使用redis的hash类型作为缓存存储模型 - redisTemplate.opsForHash().put(id.toString(), key.toString(), value); - redisTemplate.expire(id.toString(), CACHE_TIME_IN_MINT, TimeUnit.MINUTES); + redisTemplate.opsForHash().put(id.toString(), encryptionKey(key.toString()), value); + + /** + * 根据业务的不同,设置不同的缓存时间,解决掉缓存雪崩 + */ + if (id.equals("com.sunyo.wlpt.message.bus.service.mapper.VirtualHostMapper")) { + // 设置缓存时间 + redisTemplate.expire(id.toString(), random(1, 3), TimeUnit.HOURS); + } + + if (id.equals("com.sunyo.wlpt.message.bus.service.mapper.UserMessageBindingMapper")) { + // 设置缓存时间 + redisTemplate.expire(id.toString(), random(60, 100), TimeUnit.MINUTES); + } + + if (id.equals("com.sunyo.wlpt.message.bus.service.mapper.UserInfoMapper")) { + // 设置缓存时间 + redisTemplate.expire(id.toString(), random(30, 50), TimeUnit.MINUTES); + } + } + + /** + * + */ + public int random(int low, int high) + { + int num = ((int) (Math.random() * (high - low))) + low; + return num; } /** @@ -79,7 +110,7 @@ public class RedisCache implements Cache { { RedisTemplate redisTemplate = getRedisTemplate(); //根据key 从redis的hash类型中获取数据 - return redisTemplate.opsForHash().get(id.toString(), key.toString()); + return redisTemplate.opsForHash().get(id.toString(), encryptionKey(key.toString())); } /** @@ -133,7 +164,7 @@ public class RedisCache implements Cache { /** * 封装一个对key进行md5处理方法 */ - private String getKeyToMD5(String key) + private String encryptionKey(String key) { return DigestUtils.md5DigestAsHex(key.getBytes()); } -- libgit2 0.24.0