Redis入门
视频学习:黑马程序员Java项目实战瑞吉外卖
部分内容参考:Kyle’s Blog
Redis入门
Redis简介
Redis是一个开源的内容中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。官网:https://redis.io
Redis是用C语言开发的一个开源的、高性能的键值对(key-value)数据库,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。它存储的value类型比较丰富,也被称为结构化NoSql数据库
NoSql (Not Only Sql),不仅仅是SQL,泛指非关系型数据库,NoSql数据库并不是要取代关系型数据库,而是关系型数据库的补充
关系型数据库(RDBMS):MySQL、Oracl、DB2、SQLServer
非关系型数据库(NoSql):Redis、Mongo DB、MemCachedRedis应用场景:缓存、消息队列、任务队列、分布式锁
下载与安装
- Windows 版:https://github.com/microsoftarchive/redis/releases
- Linux 版:https://download.redis.io/releases/
Windows安装
下载对应版本的.zip
压缩包,直接解压
Linux安装
- 将Redis安装包上传到Linux (FinalShell等工具)
- 解压安装包:
tar -zxvf redis-xxx.tar.gz -C /usr/local
,路径通常解压到/usr/local
- 安装Redis的依赖环境gcc,命令:
yum install gcc-c++
- 进入
/usr/local/redis根目录
,进行编译:make
- 进入redis的
src目录
,进行安装:make install
服务启动与停止
Linux启动与停止
进入到
/src
目录下,执行redis-server
即可启动服务,默认端口号为6379
1
./redis-server
Linux设置后台运行
进入到redis根目录下,修改配置
redis.conf
文件1
vim redis.config
在文件中进行关键字搜索:直接输入
/关键字
然后enter即可。类似ctrl+f
找到
daemonize on
字段,将其修改为daemonize yes
在redis根目录以
redis.conf
作为配置文件在后台运行1
2
3
4[root@localhost redis-4.0.0]# src/redis-server ./redis.conf
40753:C 06 Jul 20:59:49.460 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
40753:C 06 Jul 20:59:49.461 # Redis version=4.0.0, bits=64, commit=00000000, modified=0, pid=40753, just started
40753:C 06 Jul 20:59:49.461 # Configuration loaded
Linux开启密码校验
Redis默认没有开启密码,所以需要自行配置,不配置无法进行远程连接
修改
redis.conf
配置文件,找到requirepass
这行,将其注释去掉,在后面写上自己的密码然后杀掉原进程再重新启动:
src/redis-server ./redis.conf
此时直接进行客户端登录会出现以下状况:这是因为没有输入密码所致
然后使用
auth password
命令输入密码,就能访问到数据库(此时为空)也可以在客户端登录时就输入密码
1
src/redis-cli -h localhost -p 6379 -a 密码
Linux开启远程连接
Redis启动时默认是不允许远程连接的
修改
redis.conf
配置文件找到
bind 127.0.0.1
这行,把这行注释掉(bind配置的是允许连接的ip,默认只允许本机连接;若远程连接需注释掉,或改为0.0.0.0)修改
protected-mode yes
为protected-mode no
(3.2之后加入的新特性,目的是禁止公网访问redis cache,增强redis的安全性)
之后设置防火墙,开启6379端口
1
2
3
4
5
6
7
8# 开启6379端口
firewall-cmd --zone=public --add-port=6379/tcp --permanent
# 设置立即生效
firewall-cmd --reload
# 查看开放的端口
firewall-cmd --zone=public --list-ports设置完成后kill掉redis进程,然后再重新启动
远程连接Linux的Redis:
在本地Redis的安装目录下,使用
shift+右键
,打开PowerShell
在此之前:
修改之后:
Redis数据类型
介绍
Redis存储的是key-value结构的数据,其中key是字符串类型,value有5中常用的数据类型
- 字符串:String
- 哈希:Hash
- 列表:List
- 集合:Set
- 有序集合:Sorted Set
常用命令
更多命令可以查看官方文档:https://www.redis.net.cn
字符串(String)
命令 | 描述 |
---|---|
SET key value | 设置指定key的值 |
GET key | 获取指定key的值 |
SETEX key seconds value | 设置指定key的值,并将key的过期时间设为seconds秒 |
SETNX key value | 只有在key不存在时设置key的值 |
简单演示
哈希(Hash)
Redis Hash
是一个String
类型的Field
和Value
的映射表,Hash
特别适合用于存储对象
命令 | 描述 |
---|---|
HSET key field value | 将哈希表key 中的字段field的值设为value |
HGET key field | 获取存储在哈希表中指定字段的值 |
HDEL key field | 删除存储在哈希表中的指定字段 |
HKEYS key | 获取哈希表中所有字段 |
HVALS key | 获取哈希表中所有值 |
HGETALL key | 获取在哈希表中指定key的所有字段和值 |
简单演示
列表(List)
Redis List
是简单的字符串列表,按照插入顺序排序
命令 | 描述 |
---|---|
LPUSH key value1 [value2] | 将一个或多个值插入到列表头部 |
LRANGE key start stop | 获取列表指定范围内的元素 |
RPOP key | 移除并获取列表最后一个元素 |
LLEN key | 获取列表长度 |
BRPOP key1 [key2] timeout | 移出并获取列表的最后一个元素 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 |
简单演示
集合(Set)
Redis set
是String
类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据
命令 | 描述 |
---|---|
SADD key member1 [member2] | 向集合添加一个或多个成员 |
SMEMBERS key | 返回集合中的所有成员 |
SCARD key | 获取集合的成员数 |
SINTER key1 [key2] | 返回给定所有集合的交集 |
SUNION key1 [key2] | 返回所有给定集合的并集 |
SDIFF key1 [key2] | 返回给定所有集合的差集 |
SREM key member1 [member2] | 移除集合中一个或多个成员 |
有序集合(Sorted Set)
Redis Sorted Set
有序集合是String
类型元素的集合,且不允许重复的成员。每个元素都会关联一个double
类型的分数(score
) 。Redis
正是通过分数来为集合中的成员进行从小到大排序。有序集合的成员是唯一的,但分数却可以重复。
命令 | 描述 |
---|---|
ZADD key score1 member1 [score2 member2] | 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
ZRANGE key start stop [WITHSCORES] | 通过索引区间返回有序集合中指定区间内的成员 |
ZINCRBY key increment member | 有序集合中对指定成员的分数加上增量increment |
ZREM key member [member …] | 移除有序集合中的一个或多个成员 |
简单演示
通用命令
命令 | 描述 |
---|---|
KEYs pattern | 查找所有符合给定模式(pattern)的key |
EXISTs key | 检查给定key是否存在 |
TYPE key | 返回key所储存的值的类型 |
TTL key | 返回给定key的剩余生存时间(TTL, time to live),以秒为单位 |
DEL key | 该命令用于在key存在是删除key |
在Java中操作Redis
介绍
- Redis的Java客户端有很多,官方推荐的有三种
Jedis
Lettuce
Redisson
- Spring对Redis客户端进行了整合,提供了SpringDataRedis,在Spring Boot项目中还提供了对应的Starter,即
spring-boot-starter-data-redis
Jedis
Jedis了解一下即可,大多数情况下使用SpringDataRedis
使用Jedis的步骤
- 获取连接
- 执行操作
- 关闭连接
在此之前我们需要导入一下Jedis的maven坐标
1
2
3
4
5<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>编写测试类
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
class RedisTestApplicationTests {
void contextLoads() {
//1. 获取连接
Jedis jedis = new Jedis("localhost", 6379);
//2. 执行具体操作
jedis.set("name", "wzy");
jedis.hset("stu", "name", "Jerry");
jedis.hset("stu", "age", "18");
jedis.hset("stu", "num", "4204000400");
Map<String, String> map = jedis.hgetAll("stu");
Set<String> keySet = map.keySet();
for (String key : keySet) {
String value = map.get(key);
System.out.println(key + ":" + value);
}
String name = jedis.get("name");
System.out.println(name);
//3. 关闭连接
jedis.close();
}
}输出结果
num:4204000400
name:Jerry
age:18
wzy
Spring Data Redis
SpringBoot项目中,可以使用SpringDataRedis来简化Redis(常用)。Spring Data Redis中提供了一个高度封装的类:RedisTemplate,针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:
- ValueOperations:简单K-V操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对map类型的数据操作
- ListOperations:针对list类型的数据操作
配置
创建sprongboot项目,导入Maven坐标(可以在创建时勾选redis)
1
2
3
4
5<!--Spring Boot-redis的依赖包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>完成配置类
1
2
3
4
5
6
7
8
9
10
11
12
13spring:
data:
redis:
host: 127.0.0.1 # localhost
port: 6379
#password: 123456
jedis:
pool:
max-active: 8 #最大连接数
max-wait: 1ms #连接池最大阻塞等待时间
max-idle: 4 #连接池中的最大空闲连接
min-idle: 0 #连接池中的最小空闲连接
database: 0 # 操作的0号数据库注意:这部分不同于教程多了一个data父标签,因为版本更新原本的已经过时
编写测试方法
1
2
3
4
5
6
7
8
9
10
11
class SpringbootRedisApplicationTests {
private RedisTemplate redisTemplate;
void contextLoads() {
redisTemplate.opsForValue().set("name", "wzy");
}
}然后打开
redis-cli.exe
客户端查看数据首先需要打开
redis-server.exe
服务端,但是我这里再Windows下直接打开会一闪而过,所以启动需要再redis根目录
下执行命令:redis-server.exe redis.windows.conf
然后再打开
redis-cli.exe
,查询数据库中的key:1
2127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04name"这里发现,多出了一串字符,我们存入的key是
name
。这是因为序列化所致
添加配置类
RedisConfig.java
,重新设置一下序列化器,防止出现乱码1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RedisConfig extends CachingConfigurerSupport {
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
//默认的Key序列化器为:JdkSerializationRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}然后再进行测试添加数据,然后进行数据的查询。此时结果就会显示正常。
添加数据
1
2
3
4
void contextLoads() {
redisTemplate.opsForValue().set("name2", "wzy");
}查询数据
1
2
3127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04name"
2) "name2"
可以看出,此时key显示正常。
根据key获取value发现value也存在序列化,但是这部分不用处理,因为通常的结果还会反序列化处理
1
2127.0.0.1:6379> get name2
"\xac\xed\x00\x05t\x00\x03wzy"
数据操作
字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void testRedisString(){
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("name", "wzy");
System.out.println(valueOperations.get("name"));
//设置有效时间10s
valueOperations.set("age",23,10, TimeUnit.SECONDS);
System.out.println(valueOperations.get("age"));
//如果不存在则新增
Boolean ifAbsent = valueOperations.setIfAbsent("name", "zyw");
System.out.println(ifAbsent);
}wzy
23
false哈希
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void testRedisHash(){
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.put("001", "name", "wzy");
hashOperations.put("001", "age", "23");
hashOperations.put("001", "addr", "beijing");
//只获取values
List<String> values = hashOperations.values("001");
for (String value : values) {
System.out.println(value);
}
//获取map集合
Map<String, String> map = hashOperations.entries("001");
Set<String> keySet = map.keySet();
for (String hashKey : keySet) {
System.out.println(hashKey + ":" + map.get(hashKey));
}
}wzy
23
beijing
name:wzy
age:23
addr:beijingList
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void testList() {
ListOperations listOperations = redisTemplate.opsForList();
//存数据
listOperations.leftPush("listData", "A");
listOperations.leftPushAll("listData", "B", "C", "D");
List<String> testDatas = listOperations.range("listData", 0, -1);
//遍历
for (String tableData : testDatas) {
System.out.print(tableData + " ");
}
//获取当前list长度,用于遍历
Long size = listOperations.size("listData");
int value = size.intValue();
//遍历输出并删除
for (int i = 0; i < value; i++) {
System.out.print(listOperations.leftPop("listData") + " ");
}
//输出当前list长度
System.out.println(listOperations.size("listData"));
}Set
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void testSet() {
SetOperations setOperations = redisTemplate.opsForSet();
setOperations.add("rank", "a", "s", "ssr", "a");
//遍历输出
Set<String> tmpData = setOperations.members("rank");
for (String value : tmpData) {
System.out.print(value + " ");
}
System.out.println();
//删除a
setOperations.remove("rank", "a");
//遍历输出
tmpData = setOperations.members("rank");
for (String value : tmpData) {
System.out.print(value + " ");
}
}Zset
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
void testZset() {
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
//存值
zSetOperations.add("myZset", "a", 0.0);
zSetOperations.add("myZset", "b", 1.0);
zSetOperations.add("myZset", "c", 2.0);
zSetOperations.add("myZset", "a", 3.0);
//取值
Set<String> myZset = zSetOperations.range("myZset", 0, -1);
for (String s : myZset) {
System.out.println(s);
}
//修改分数
zSetOperations.incrementScore("myZset", "b", 4.0);
//取值
System.out.println();
myZset = zSetOperations.range("myZset", 0, -1);
for (String s : myZset) {
System.out.println(s);
}
//删除成员
zSetOperations.remove("myZset", "a", "b");
//取值
System.out.println();
myZset = zSetOperations.range("myZset", 0, -1);
for (String s : myZset) {
System.out.println(s);
}
}通用操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void testCommon() {
//查看Radia中所有key
Set<String> keys = redisTemplate.keys("*");
for (String key : keys) {
System.out.println(key);
}
//判断某个key是否存在
System.out.println(redisTemplate.hasKey("wzy"));
//删除指定key
redisTemplate.delete("name");
//获取指定key的数据类型
System.out.println(redisTemplate.type("001"));
}name
\xac\xed\x00\x05t\x00\x04name
001false
HASH