Redis介绍
redis是基于内存进行存储,支持key-value的存储形式,结构简单,没有数据表的概念(非存储类型),可以直接用键值对的方式完成数据的管理,能够支持五种存储类型(String、list、hash、set、zset)
通过下列结构理解redis的存储形式
{key:
value:{key:value}(hash)}
Redis下载安装
链接:https://github.com/antirez/redis
具体步骤不想写,傻瓜式安装
linux安装教程:https://blog.csdn.net/qq_33753147/article/details/127382907
windows安装教程:https://blog.csdn.net/Leewayah/article/details/129427599
Redis五大常用存储类型简介
string:字符串类型
redis中最基本的存储类型,它是由字节组成的序列,在redis中是二进制的,该类型支持任何格式的数据,例如能够支持int类型的原子加减操作,常用的基本操作命令有set、get、del操作。
list:列表
redis列表是简单的字符串列表,它相当于java中的arraylist和linkedlist的结合,是按照存储顺序进行排序的不可重复列表,它支持用户从头部或尾部进行数据元素的添加、获取。
hash:哈希
redis的哈希和java中的hash是同样的原理,都是以键值对的形式存储、key唯一、无序,比较适合存储对象。
set:集合
redis的集合是string类型的无序集合,和java中学习的set集合一样,都是基于哈希实现的,都是无序不重复的。
zset:有序集合
redis的zset不同于java中的set,他是一个有序集合,存储形式以score-value的形式存储,与set集合不同的是,在set集合的基础上增加了score这个排序权重,因此zset可以实现排序的特点(默认的是升序排序),score的值是可以重复的,但是value的值依旧不可重复。
Windows系统开启redis服务
首先我们进入redis的安装目录
新手可以选择这种方式来启动redis,第一步我们先开启redis的服务端(redis-server.exe),服务端开启如果显示的内容和下面一样,那么就说明服务端已经开启成功,记住服务端开启以后不要关闭,我们把它缩小就好。
服务端开启后点击redis-cli开启客户端,此时我们的redis就已经启动完成!
Springboot整合Redis
使用idea创建springboot项目,具体的流程就不详细介绍了,因为我也是上班时间没事的话写点,整合redis可以在创建项目的时候就引入依赖,也可以后续在pom文件中添加redis依赖,具体如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
yml文件配置
spring:
redis:
port: 6379
host: localhost
jedis:
pool:
max-active: 0
max-idle: 0
max-wait: -1ms
min-idle: 0
# redis服务器地址(默认为localhost)
host: localhost
# redis端口(默认为6379)
port: 6379
# redis连接超时时间(单位毫秒)
timeout: 0
# redis连接池配置
pool:
# 最大可用连接数(默认为0,负数表示无限)
max-active: 0
# 最大空闲连接数(默认为0,负数表示无限)
max-idle: 0
# 最小空闲连接数(默认为0,该值只有为正数才有用)
min-idle: 0
添加完依赖和yml配置,我们就可以使用redis进行存储操作了,因为redis是使用内存对数据进行存储操作,所以我们一般都是将redis写在控制层(controller层),便于数据的管理,话不多说直接上代码
@RestController
@ResponseBody
@Transactional
public class StudentHandler {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StudentServiceImpl studentService;
@RequestMapping(value = "/insert",method = RequestMethod.POST)
public StudentEum insertStu(@RequestBody Student student){
if (studentService.insertStu(student)>0){
BoundHashOperations stu = redisTemplate.boundHashOps("student");
stu.put(student.getSname(),student);
return StudentEum.OK;
}else {
return StudentEum.FAIL;
}
}
}
自动注入RedisTemplate,用于使用redis操作
这里是一个添加用户的操作,当然只作为demo,一般情况下用户的信息或者是查询量并不是很大的数据,我们也并不会都去存储到redis中,这里只作为一个案例去便于大家理解。比如当前这个接口存储的信息是查询量比较大的,那么我们就会在这个接口将信息存储到数据库的时候,也将它存储到redis中,这里我们使用的是hash存储类型,存储的是一个对象,因为redis是使用二进制进行传输,所以我们存储的对象要进行序列化的操作
信息添加完之后,比如用户这时候需要查看信息,那么我们实现查看信息的接口
//通过名字查看学生分数等信息
@RequestMapping(value = "/selectBySname",method = RequestMethod.GET)
public Object selectBySname(String sname){
Map student = redisTemplate.opsForHash().entries("student");
if (student.get(sname)!=null){
System.out.println("数据从redis中取出来了");
return student.get(sname);
}
System.out.println("数据从数据库中取出来了");
List<Student> list = studentService.selectBySname(sname);
if (!list.isEmpty()){
return list;
}else {
return "查无此人";
}
}
这个接口的大概流程就是,用户在查看信息的时候呢,我们的接口会先到redis中进行一个判断,查看redis是否存在此数据,如果redis中没有,我们才会去数据库中查找,这样的做的目的就已经体现了redis的主要作用,其实就是为了保护数据库,因为redis是基于内存存储的,他的读写速度是非常快的,针对于访问量比较大的数据,可以保护数据库,以防宕机。
Redis这么牛?难道redis不会出现问题吗?
答案肯定是会的,常见面试题,redis的雪崩、穿透、击穿。。。。。
什么是雪崩?
雪崩就是大量的缓存数据集中过期,或者呢缓存服务器宕机,那么此时大量的访问请求就会蜂拥而至的跑到数据库,造成数据库的宕机。
如何避免雪崩?
1.我们可以给各个缓存数据设置随机的过期时间,这样就可以避免集中过期的情况
2.服务器宕机可以搭建redis集群、哨兵模式解决宕机问题(具体的可以参考大神博主,上班中时间不多后面有空呢可以出步骤)
什么是击穿?
缓存击穿,当某个数据非常热点,并且在不停的扛着高并发的请求,当这个数据失效的时候,那么这种高并发就会击破缓存,直接请求至数据库,导致性能下降。
如果解决缓存击穿?
1.暴力点的我们可以给热点数据设置的过期时间为永不过期(默认)
2.对访问量进行统计,当某一时间段内请求达到一定次数的时候,我们将缓存数据设置为永不过期
什么是穿透?
缓存中和数据库中都没有这个数据(比如恶意攻击的用户输入%#¥……¥%……¥),数据库中一定是没有这些数据的,那么这些恶意攻击的请求就会造成服务器的内存消耗。
如何防止穿透?
1.采用请求参数校验的方式,防止恶意输入无效内容
2.缓存中和数据库中没有这个值,那么在第一次请求数据库的时候,不管查到什么值,我们都设置一个值(比如null)存入到redis中并设置一个过期时间,那么下次取值就会从缓存中取值,而不是再次访问数据库。
3.其他方式(布隆过滤器,感兴趣的可以去查查看,博主也在学习,后续可以出步骤,大家共同学习进步!)