redis相关面试题:
1.redis支持哪些数据类型?String List Hash(Map) Set StoredSet(有排序Set)
2.这些数据类型使用的时候怎么用?
String:建议存储比较独立的数据,并且多个String没有关联
List:建议存储有顺序要求的数据
Hash:存储key-value数据,并且他们有关联关系,存储一个对象数据
Set:存储无序数据,要求没有重复
StoredSet:有序Set,存储例如排行榜数据,每个元素有权重
3.为什么使用redis?快
redis:内存cpu的性能
数据库:磁盘读写性能
4.有点:数据结构简单,key-value
nosql,非关系数据
5.常见问题:
缓存穿透:
是指查询一个存在的数据,由于cache不命中,没有一个请求提前往redis中放数据,都去数据库查,
造成系统性能下降
=================修改之前的代码
/**缓存穿透:
* 1.假设有10000个人同时并发调用这段代码,结果都没有命中
*/
List userList=(List) redisTemplate.opsForValue().get(“userList”);
if(nulluserList)
{
System.out.println(“去数据库拿”);
//缓存没有去数据库拿
/**
* 2.结果10000个请求都去访问数据库,从数据库查询数据(需要时间长,用户体验稍微不好),这就是鼎鼎有名的缓存穿透
*/
userList=userMapper.selectAll();
//拿了之后放入缓存
redisTemplate.opsForValue().set(“userList”, userList);
}else
{
System.out.println(“从缓存中拿”);
}
return userList;
=============这是controller中原来的代码:
ModelAndView mav=new ModelAndView();
mav.setViewName(“list”);//springboot工程跳转html的路径默认前缀是 templates目录,后缀是.html,
mav.addObject(“userList”, userServiceIfac.getAllUser());
return mav;
==========================可以采用双重检测来改进缓存穿透问题
service代码:
List userList=(List) redisTemplate.opsForValue().get(“userList”);
if(nulluserList)//第一次检测
{
//缓存没有去数据库拿
/**
* 2.结果10000个请求都去访问数据库,从数据库查询数据(需要时间长,用户体验稍微不好),这就是鼎鼎有名的缓存穿透
*/
synchronized (this) {//synchronized能够把并发执行的代码变得同步执行,也就是顺序执行
userList=(List) redisTemplate.opsForValue().get(“userList”);
if(nulluserList) {//第二次检测
System.out.println(“去数据库拿”);
userList=userMapper.selectAll();
//拿了之后放入缓存
redisTemplate.opsForValue().set(“userList”, userList);
}else
{
System.out.println(“从缓存中拿”);
}
}
}else
{
System.out.println(“从缓存中拿”);
}
return userList;
controller中模拟并发请求的代码:
@RequestMapping(“listUser”)
public ModelAndView listUser()
{
//模拟在当次请求中并发调用getAllUser方法10000次
// ModelAndView mav=new ModelAndView();
// mav.setViewName(“list”);//springboot工程跳转html的路径默认前缀是 templates目录,后缀是.html,
// mav.addObject(“userList”, userServiceIfac.getAllUser());
ModelAndView mav=new ModelAndView();
//1.首先要有一个线程,多个线程的同时启动,那就是并发执行
Runnable r=new Runnable() {
@Override
public void run() {
userServiceIfac.getAllUser();
}
};
//2.模拟一个线程池,执行10000次提交
ExecutorService executorService=Executors.newFixedThreadPool(25);
for(int i=0;i<10000;i++)
{
executorService.submit(r);
}
mav.setViewName("list");
mav.addObject("userList", null);
return mav;
}
====================缓存击穿
1.如果缓存和数据库中都没有数据,那么用户一直恶意请求怎么办?
那么就给数据一个默认值,这个默认值也可以是一个标识,标识这个数据没有,不用再查了
缓存雪崩:
是指cache设置了相同的过期时间,导致cache在同一时间失效,请求全部转发到DB,造成DB压力过大
瞬间雪崩,给key设置不同的过期时间。