Redis基础
279665
初识Redis
Redis是一个键值型的NoSQL数据库
- 键值型:键值型指Redis中存储的数据都是以Key-Value键值对的形式存储,可以是字符串、数值甚至Json
- NoSQL则是相对于传统关系型数据库而言,有很大差异的一种数据库
NoSQL数据库
NoSql可以翻译做Not Only Sql(不仅仅是SQL),或者是No Sql(非Sql的)数据库。是相对于传统关系型数据库而言,有很大差异的一种特殊的数据库,因此也称之为非关系型数据库。
结构化与非结构化
传统关系型数据库是结构化数据,创建表时有严格的约束信息,如字段名,字段类型,这些约束必须遵循。
而NoSQL数据库则是非结构化数据,没有严格的约束信息,可以是键值型,文档型,甚至是图格式
关联与非关联
传统数据库的表与表之间存在关联关系,例如外键约束,而NoSQL数据库则不存在关联关系,数据之间没有约束,维护关系要么考业务逻辑,要么靠数据之间耦合
查询方式
传统的数据库必须基于SQL语句来做查询,语法较为统一
1 | SELECT * FROM user WHERE id = 1 |
而NoSQL数据库则没有SQL语句,查询方式根据不同的数据库而不同。
1 | Redis: get user:1 |
事务
传统关系型数据库能满足事务的ACID原则(原子性、一致性、独立性及持久性)
而非关系型数据库汪汪不支持事务,或者不能要个保证ACID的特性,只能实现基本的一致性
总结
| SQL | NoSQL | |
|---|---|---|
| 数据结构 | 结构化(Structured) | 非结构化 |
| 数据关联 | 关联的(Relational) | 无关联的 |
| 查询方式 | SQL查询 | 非SQL |
| 事务特性 | ACID | BASE |
| 存储方式 | 磁盘 | 内存 |
| 扩展性 | 垂直 | 水平 |
*存储方式
- 关系型数据库基于
磁盘进行存储,会有大量的磁盘IO,对性能有一定影响 - 非关系型数据库,操作更多的是依赖于
内存来操作,内存的读写速度非常快,性能自然会好一些- 扩展性
- 关系型数据库集群模式一般是主从,主从数据一致,起到数据备份的作用,称为
垂直扩展。 - 非关系型数据库可以将数据拆分,存储在不同机器上,可以保存海量数据,解决内存大小有限的问题。称为
水平扩展。 - 关系型数据库因为表之间存在关联关系,如果做水平扩展会给数据查询带来很多麻烦
认识Redis
Redis全称是Remote Dictionary Server远程词典服务器,是一个基于内存的键值型NoSQL数据库。
特点:
- 键值(Key-Value)型,Value支持多种不同的数据结构,功能丰富
- 单线程,每个命令具有原子性
- 低延迟,速度快(基于内存、IO多路复用、良好的编码)
- 支持数据持久化
- 支持主从集群、分片集群
- 支持多语言客户端
Redis官网:https://redis.io/
下载Redis
检查gcc环境
Redis是基于C语言编写的,因此首先需要安装Redis需要gcc依赖:
- 检查是否安装了gcc
1
gcc --version
- 如果未安装则需要安装gcc
1
yum install -y gcc tcl
下载Redis
- 进入要安装的文件夹
1 | cd /usr/local/src |
- 下载并解压redis
1
2wget https://download.redis.io/releases/redis-7.2.0.tar.gz
tar -zxvf redis-7.2.0.tar.gz - 进入redis安装目录
1
cd redis-7.2.0
- 编译并安装
1
make && make install
- 查看是否安装成功
1
2cd /usr/local/bin
ll - 可以在任意目录下运行redis
该目录已经默认配置到环境变量,因此可以在任意目录下运行这些命令。其中:
- redis-cli:是redis提供的命令行客户端
- redis-server:是redis的服务端启动脚本
- redis-sentinel:是redis的哨兵启动脚本
启动Redis
redis的启动方式有很多种,例如:
- 默认启动
- 指定配置启动
- 开机自启
默认启动
安装完成后,在任意目录输入redis-server命令即可启动Redis:
1 | redis-server |

这种启动方式属于前台启动,会阻塞整个会话窗口,窗口关闭则redis也会关闭。
指定配置启动
如果要让Redis以后台方式启动,则必须修改Redis配置文件,就在之前解压的redis安装包下(/usr/local/src/redis-7.2.0),名字叫redis.conf:
先将这个配置文件备份一份:
1 | cp redis.conf redis.conf.bck |
然后修改redis.conf文件中的一些配置:
1 | # 允许访问的地址,默认是127.0.0.1,会导致只能在本地访问。修改为0.0.0.0则可以在任意IP访问,生产环境不要设置为0.0.0.0 |
Redis的其它常见配置:
1 | # 监听的端口 |
1 | # 进入redis安装目录 |
1 | ps -ef | grep redis |
1 | # 利用redis-cli来执行 shutdown 命令,即可停止 Redis 服务, |
开机自启
我们也可以通过配置来实现开机自启。
PS:需要先将前面的Redis进程杀死,否则会启动失败。
1 | #查看当前进程 |
首先,新建一个系统服务文件
1 | vi /etc/systemd/system/redis.service |
1 | [Unit] |
接着重载系统:
1 | systemctl daemon-reload |
就能使用以下这组命令来操作redis了
1 | # 启动redis |
执行以下命令,实现开机自启
1 | systemctl enable redis |
Redis桌面客户端
安装完Redis后,我们可以使用Redis客户端来实现对数据的CRUD。
Redis客户端包括:
- 命令行客户端
- 图形化桌面客户端
- 编程客户端
命令行客户端
Redis安装完成后就自带了Redis命令行客户端,可以使用redis-cli命令来连接Redis服务器。
使用方式:redis-cli [options] [commonds]
1 | redis-cli -h 127.0.0.1 -p 6379 |
常见的options有:
- -h 127.0.0.1:指定要连接的redis节点的IP地址,默认是127.0.0.1
- -p 6379:指定要连接的redis节点的端口,默认是6379
- -a 123321:指定redis的访问密码
其中的commonds就是Redis的操作命令,例如:
- ping:与redis服务端做心跳测试,服务端正常会返回pong
不指定commond时,会进入redis-cli的交互控制台:
图形化桌面客户端
Redis官方没有提供Windows版本的图形化桌面客户端,但Github上有大神编写了Redis的Windows版本的图形化客户端
不过该仓库提供的为源码,需要自己编译。
在下面这个仓库可以找到安装包:https://github.com/lework/RedisDesktopManager-Windows/releases
建立连接
通过点击左上角连接到Redis服务器按钮,弹出连接对话框:

填写完基本信息后,点击
测试连接按钮,测试连接是否成功。如果
连接失败,关闭Linux防火墙后尝试再次连接。1 | systemctl stop firewalld |
Redis的Java客户端
在Redis官网中提供了各种语言的客户端,地址:https://redis.io/docs/clients/

推荐使用的Java客户端包括:
- Jedis和Letter:这两个主要提供了Redis命令对应的API,方便我们直接操作Redis,
SpringDataRedis又对这两种做了抽象和封装,故后期我们使用SpringDataRedis来操作Redis。 - Redission:在Redis基础上实现了分布式的可伸缩的java数据结构,例如Map,Queue等,而且支持跨进程的同步机制:Lock、Semaphore等来,比较适合用来实现特殊的功能需求
Jedis快速入门
- 创建项目后,引入Jedis依赖
1
2
3
4
5
6
7
8
9
10
11
12
13<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency> - 建立连接
新建单元测试类,在测试类运行前连接jedis1
2
3
4
5
6
7
8
9
10
11
12private Jedis jedis;
void setUp() {
// 1.建立连接
// jedis = new Jedis("192.168.150.101", 6379);
jedis = JedisConnectionFactory.getJedis();
// 2.设置密码
jedis.auth("123321");
// 3.选择库
jedis.select(0);
} 测试连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void testString() {
// 存入数据
String result = jedis.set("name", "虎哥");
System.out.println("result = " + result);
// 获取数据
String name = jedis.get("name");
System.out.println("name = " + name);
}
void testHash() {
// 插入hash数据
jedis.hset("user:1", "name", "Jack");
jedis.hset("user:1", "age", "21");
// 获取
Map<String, String> map = jedis.hgetAll("user:1");
System.out.println(map);
}关闭连接
1
2
3
4
5
6
void tearDown() {
if (jedis != null) {
jedis.close();
}
}
连接池
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式。
1 | public class JedisConnectionFactory { |
SpringDataRedis快速入门
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网
- 提供了对不同Redis客户端的整合(Lettuce和Jedis)
- 提供了RedisTemplate统一API来操作Redis
- 支持Redis的发布订阅模型
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的响应式编程
- 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
- 支持基于Redis的JDKCollection实现
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:
SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单。
首先,新建一个maven项目,然后按照下面步骤执行:
- 引入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.heima</groupId>
<artifactId>redis-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--common-pool-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--Jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!--Lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--Springboot起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project> - 配置Redis连接信息
1
2
3
4
5
6
7
8
9
10
11spring:
redis:
host: 192.168.150.101
port: 6379
password: 123321
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 100ms - 注入RedisTemplate
因为使用的是SpringBoot,所以直接自动装配注入就好了1
2
3
4
5
class RedisDemoApplicationTests {
private RedisTemplate redisTemplate;
} - 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class RedisStringTests {
private RedisTemplate edisTemplate;
void testString() {
// 写入一条String数据
redisTemplate.opsForValue().set("name", "虎哥");
// 获取string数据
Object name = stringRedisTemplate.opsForValue().get("name");
System.out.println("name = " + name);
}
}
Redis入门
Redis是典型的key-value数据库,其中key是字符串类型,value可以是多种不同的数据类型
Redis通用命令
通用命令有以下几个
| 命令 | 描述 |
|---|---|
| KEYs pattern | 查找所有符合给定模式(pattern)的key |
| EXISTs key | 检查给定key是否存在 |
| TYPE key | 返回key所储存的值的类型 |
| TTL key | 返回给定key的剩余生存时间(TTL, time to live),以秒为单位 |
| DEL key | 该命令用于key存在时删除key |
KEYS:查看符合模板的所有key- 不建议在生产环境设备上使用,因为Redis是单线程的,执行查询的*时候会阻塞其他命令,当数据量很大的时候,使用KEYS进行模糊查询,效率很差
DEL:删除一个指定的key- 也可以删除多个key,DEL name age,会将name和age都删掉
EXISTS:判断key是否存在- EXISTS name,如果存在返回1,不存在返回0
EXPIRE:给一个key设置有效期,有效期到期时该key会被自动删除- EXPIRE name 20,给name设置20秒有效期,到期自动删除
TTL:查看一个key的剩余有效期(Time-To-Live)- TTL name,查看name的剩余有效期,如果未设置有效期,则返回-1
String类型
String类型,也就是字符串类型,是Redis中最简单的存储类型,value是字符串类型,根据字符串格式不同,又可以分为三种
- string: 普通字符串
- int: 整数
- float: 浮点数
不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同,字符串类型的最大空间不能超过512M
String的常用命令
- 格式:SET key value [EX seconds | PX milliseconds] [NX|XX]
- 功能:SET 除了可以直接将 key 的值设为 value 外,还可以指定一些参数。
- EX seconds:为当前 key 设置过期时间,单位秒。等价于 SETEX 命令。
- PX milliseconds:为当前 key 设置过期时间,单位毫秒。等价于 PSETEX 命令。
- NX:指定的 key 不存在才会设置成功,用于添加指定的 key。等价于 SETNX 命令。
- XX:指定的 key 必须存在才会设置成功,用于更新指定 key 的 value。
- 说明:如果 value 字符串中带有空格,则该字符串需要使用双引号或单引号引起来,否 则会认为 set 命令的参数数量不正确,报错。
- 格式:MSET/MSETNX key value [key value …]
- 功能:同时设置一个或多个 key-value 对。
- 说明:如果某个给定 key 已经存在,那么
MSET会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用MSETNX命令:它只会在所有给定 key 都不存在的情况下进行设置操作。MSET/MSETNX 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况不可能发生。该命令永不失败
- 格式:MGET key [key …]
- 功能:返回
所有(一个或多个)给定 key 的值。- 说明:如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。 因此,该命令永不失败。
- 格式:INCRBY key increment 或 DECRBY key decrement
- 功能:将 key 中存储的数字值增加/减少指定的数值,这个数值
只能是整数,可以是负数,但不能是小数。- 说明:如果 key 不存在,那么 key 的值会先被初始化为 0,然后再执行增/减操作。如果值不能表示为数字,那么返回一个错误提示。如果执行正确,则返回增/减后的值。
- 格式:INCRBYFLOAT key increment
- 功能:为 key 中所储存的值加上
浮点数增量 increment 。- 说明:与之前的说明相同。没有 decrbyfloat 命令,但 increment 为负数可以实现减操作效果。
- 格式:STRLEN key
- 功能:返回 key 所储存的字符串值的长度。
- 说明:当 key 储存的不是字符串值时,返回一个错误。
String类型典型场景
Value 为 String 类型的应用场景很多,这里仅举这种典型应用场景的例子:
(1) 数据缓存
Redis 作为数据缓存层,MySQL 作为数据存储层。应用服务器首先从 Redis 中获取数据,如果缓存层中没有,则从 MySQL 中获取后先存入缓存层再返回给应用服务器。
(2) 计数器
在 Redis 中写入一个 value 为数值型的 key 作为平台计数器、视频播放计数器等。每个有效客户端访问一次,或视频每播放一次,都是直接修改 Redis 中的计数器,然后再以异步方式持久化到其它数据源中,例如持久化到 MySQL。
(3) 共享 Session
对于一个分布式应用系统,如果将类似用户登录信息这样的Session 数据保存在提供登录服务的服务器中,那么如果用户再次提交像收藏、支付等请求时可能会出现问题:在提供收藏、支付等服务的服务器中并没有该用户的 Session 数据,从而导致该用户需要重新登录。
此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从 Redis 中查找相应的 Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。这样就不会引发“重新登录”问题。
(4) 限速器
现在很多平台为了防止 DoS(Denial of Service,拒绝服务)攻击,一般都会限制一个 IP 的访问次数,如不能在一秒内访问超过 n 次。而 Redis 可以结合 key 的过期时间与 incr 命令来完成限速
功能,充当限速器。
1 | // 客户端每提交一次请求,都会执行下面的代码 |
Hash型Value操作
Redis 存储数据的 Value 可以是一个Hash类型。Hash 类型也称为 Hash 表、字典等。
Hash 表就是一个映射表 Map,也是由键-值对构成,为了与整体的 key 进行区分,这里的键称为 field,值称为 value。注意,Redis 的 Hash 表中的 field-value 对均为 String 类型。
- Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD操作。
Hash常用命令
| 命令 | 描述 |
|---|---|
| HSET key field value | 添加或者修改hash类型key的field的值 |
| HGET key field | 获取一个hash类型key的field的值 |
| HMSET | 批量添加多个hash类型key的field的值 |
| HMGET | 批量获取多个hash类型key的field的值 |
| HGETALL | 获取一个hash类型的key中的所有的field和value |
| HKEYS | 获取一个hash类型的key中的所有的field |
| HINCRBY | 让一个hash类型key的字段值自增并指定步长 |
| HSETNX | 添加一个hash类型的key的field值,前提是这个field不存在,否则不执行 |
- 格式:HSET key field value
- 功能:将哈希表 key 中的域 field 的值设为 value 。
- 说明:如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。如果域 field 已经存在于哈希表中,旧值将被
覆盖。如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1 。如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0 。
- 格式:HGET key field
- 功能:返回哈希表 key 中给定域 field 的值。
- 说明:当给定域不存在或是给定 key 不存在时,返回 nil 。
- 格式:HMSET key field value [field value …]
- 功能:同时将多个 field-value (域-值)对设置到哈希表 key 中。
- 说明:此命令会
覆盖哈希表 key 中已存在的域。如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。
- 格式:HMGET key field [field …]
- 功能:按照给出顺序返回哈希表 key 中,一个或多个给定域的值。
- 说明:如果给定的域不存在或是给定 key 不存在,那么返回一个 nil 值。
- 格式:HGETALL key
- 功能:返回哈希表 key 中,所有的域和值。
- 说明:在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
- 格式:HSETNX key field value
- 功能:将哈希表 key 中的域 field 的值设为 value ,当且仅当域 field 不存在。
- 说明:若域 field 已经存在,该操作无效。如果 key 不存在,一个新哈希表被创建并执行 HSETNX 命令。
- 格式:HDEL key field [field …]
- 功能:删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
- 说明:返回被成功删除的域的数量,不包括被忽略的域。
- 格式:HEXISTS key field
- 功能:查看哈希表 key 中,给定域 field 是否存在。
- 说明:返回 1 表示存在,返回 0 表示不存在。
- 格式:HINCRBY key field increment
- 功能:为哈希表 key 中的域 field 的值加上
增量 increment,hincrby 命令只能增加整数值,而 hincrbyfloat 可以增加小数值。 。- 说明:增量也可以为
负数,相当于对给定域进行减法操作。如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。如果域 field 不存在,那么在执行命令前,域的值被初始化为 0 。
应用场景
Hash 型 Value 非常适合存储对象数据。key 为对象名称,value 为描述对象属性的 Map,
对对象属性的修改在 Redis 中就可直接完成。其不像 String 型 Value 存储对象,那个对象是序列化过的,例如序列化为JSON 串,对对象属性值的修改需要先反序列化为对象后再修改,
修改后再序列化为 JSON 串后写入到 Redis。
List类型
Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。
特征也与LinkedList类似:
- 有序
- 元素可以重复
- 插入和删除快
- 查询速度一般
常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。
List的常见命令
| 命令 | 描述 |
|---|---|
| LPUSH key element … | 向列表左侧插入一个或多个元素 |
| LPOP key | 移除并返回列表左侧的第一个元素,没有则返回nil |
| RPUSH key element … | 向列表右侧插入一个或多个元素 |
| RPOP key | 移除并返回列表右侧的第一个元素 |
| LRANGE key star end | 返回一段角标范围内的所有元素 |
| BLPOP和BRPOP | 与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil |

