作者 王勇

完善mybatis的二级缓存

@@ -15,6 +15,16 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -15,6 +15,16 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
15 /** 15 /**
16 * @author 子诚 16 * @author 子诚
17 * Description:自定义Redis作为mybatis二级缓存实现 17 * Description:自定义Redis作为mybatis二级缓存实现
  18 + * 问题描述:缓存穿透、缓存雪崩
  19 + * <p>
  20 + * 缓存穿透:就是说利用一些列措施,使得访问避开了缓存,直接访问数据库,使得数据库不堪重负引起的问题。比如(压测)访问数据库中不存在的数据
  21 + * 解决方案:读取数据库,不存在;依旧生成对应的key,放到缓存中,但是对应的value是null(mybatis的二级缓存是这样解决的)。
  22 + * 下次再次访问的话,就是读取缓存。
  23 + * <p>
  24 + * 缓存雪崩:是指在某一特殊时刻,缓存中的缓存全部失效,然后这一时刻又有大量的数据库访问,导致数据库不堪重负。
  25 + * 解决方案:根据业务的不同设置不同的缓存失效时间。
  26 + * 比如:这个项目,做了3个namespace的缓存,其中一个namespace,共有5个Mapper指向它。所以选择使用范围内的随机值,来做缓存失效时间
  27 + * <p>
18 * 时间:2020/8/6 9:37 28 * 时间:2020/8/6 9:37
19 */ 29 */
20 public class RedisCache implements Cache { 30 public class RedisCache implements Cache {
@@ -30,11 +40,6 @@ public class RedisCache implements Cache { @@ -30,11 +40,6 @@ public class RedisCache implements Cache {
30 private static final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 40 private static final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
31 41
32 /** 42 /**
33 - * 缓存对象的是失效时间,30分钟  
34 - */  
35 - private static final long CACHE_TIME_IN_MINT = 30;  
36 -  
37 - /**  
38 * 当前放入缓存的mapper的namespace 43 * 当前放入缓存的mapper的namespace
39 */ 44 */
40 private final String id; 45 private final String id;
@@ -67,8 +72,34 @@ public class RedisCache implements Cache { @@ -67,8 +72,34 @@ public class RedisCache implements Cache {
67 { 72 {
68 RedisTemplate redisTemplate = getRedisTemplate(); 73 RedisTemplate redisTemplate = getRedisTemplate();
69 // 使用redis的hash类型作为缓存存储模型 74 // 使用redis的hash类型作为缓存存储模型
70 - redisTemplate.opsForHash().put(id.toString(), key.toString(), value);  
71 - redisTemplate.expire(id.toString(), CACHE_TIME_IN_MINT, TimeUnit.MINUTES); 75 + redisTemplate.opsForHash().put(id.toString(), encryptionKey(key.toString()), value);
  76 +
  77 + /**
  78 + * 根据业务的不同,设置不同的缓存时间,解决掉缓存雪崩
  79 + */
  80 + if (id.equals("com.sunyo.wlpt.message.bus.service.mapper.VirtualHostMapper")) {
  81 + // 设置缓存时间
  82 + redisTemplate.expire(id.toString(), random(1, 3), TimeUnit.HOURS);
  83 + }
  84 +
  85 + if (id.equals("com.sunyo.wlpt.message.bus.service.mapper.UserMessageBindingMapper")) {
  86 + // 设置缓存时间
  87 + redisTemplate.expire(id.toString(), random(60, 100), TimeUnit.MINUTES);
  88 + }
  89 +
  90 + if (id.equals("com.sunyo.wlpt.message.bus.service.mapper.UserInfoMapper")) {
  91 + // 设置缓存时间
  92 + redisTemplate.expire(id.toString(), random(30, 50), TimeUnit.MINUTES);
  93 + }
  94 + }
  95 +
  96 + /**
  97 + *
  98 + */
  99 + public int random(int low, int high)
  100 + {
  101 + int num = ((int) (Math.random() * (high - low))) + low;
  102 + return num;
72 } 103 }
73 104
74 /** 105 /**
@@ -79,7 +110,7 @@ public class RedisCache implements Cache { @@ -79,7 +110,7 @@ public class RedisCache implements Cache {
79 { 110 {
80 RedisTemplate redisTemplate = getRedisTemplate(); 111 RedisTemplate redisTemplate = getRedisTemplate();
81 //根据key 从redis的hash类型中获取数据 112 //根据key 从redis的hash类型中获取数据
82 - return redisTemplate.opsForHash().get(id.toString(), key.toString()); 113 + return redisTemplate.opsForHash().get(id.toString(), encryptionKey(key.toString()));
83 } 114 }
84 115
85 /** 116 /**
@@ -133,7 +164,7 @@ public class RedisCache implements Cache { @@ -133,7 +164,7 @@ public class RedisCache implements Cache {
133 /** 164 /**
134 * 封装一个对key进行md5处理方法 165 * 封装一个对key进行md5处理方法
135 */ 166 */
136 - private String getKeyToMD5(String key) 167 + private String encryptionKey(String key)
137 { 168 {
138 return DigestUtils.md5DigestAsHex(key.getBytes()); 169 return DigestUtils.md5DigestAsHex(key.getBytes());
139 } 170 }