1. 在高并发的时候,这个程序存在缓存穿透的问题
假如有1万人进来,有200人都同时查询不到数据库,所以要进行200次数据库查询。合理的情况应该有一个人进来查询数据,把数据放到缓存里,剩下的9999人从redis取数据
解决办法:使用同步锁和双重检测法
/**注入springboot自动配置的redisTemplate**/
//打卡排行榜
public List<Rank> getCheckRank(){
//字符串的序列化器
RedisSerializer redisSerializer=new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
//查询缓存
List<Rank> rankList=(List<Rank>) redisTemplate.opsForValue().get("checkRank");
//双重检测锁
if(null==rankList) {
synchronized (this) {
//从redis获取一下
rankList = (List<Rank>) redisTemplate.opsForValue().get("checkRank");
if (null == rankList) {
//缓存为空,查询一遍数据库
rankList = weightMapper.getCheckRank();
//把数据库查询出来的数据,放入redis中
redisTemplate.opsForValue().set("checkRank", rankList);
}
}
}
return rankList;
}
2. 使用多线程验证
在controller里添加以下代码进行测试,一般线程池的个数根据cpu数取值,一个cpu可以创建两个线程池。
@ResponseBody
@GetMapping("/checkRankTest")
public Object checkRankTest() {
Runnable runnable=new Runnable() {
@Override
public void run() {
weightService.getCheckRank();
}
};
//创建25个线程池,起10000个线程提交
ExecutorService executorService= Executors.newFixedThreadPool(25);
for(int n=0;n<100000;n++)
{
executorService.submit(runnable);
}
return weightService.getCheckRank();
}
3. 运行结果:只运行了一次mysql查询,其他都是从redis访问获得