Redis的基本数据类型

87 阅读10分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

下载与安装

作为缓存数据库,后期肯定是要部署在Linux系统上的,但鉴于是初学,我们先在Windows上操作一下,下载地址:github.com/microsoftar…

下载完成后解压即可。

\

执行解压后文件夹中的redis-server.exe即可启动redis:

出现下图则启动成功:

端口号默认为6379。

\

刚才我们启动的是redis的服务端,那么该如何操作redis呢?我们还需要启动它的客户端,执行文件夹中的redis-cli.exe:

基本操作

既然是数据库,那就少不了与数据打交道,我们先来看看如何通过redis进行数据的保存和读取。

\

首先是保存数据:

set key value

redis中的数据都是以键值对进行存储的,所以在保存数据的时候只需要指定数据的键名和键值即可,读取的时候通过键名获取:

get key

若是指定的key不存在,则会返回空(nil)。

\

redis也提供了帮助命令,用于查询一些指令的用法:

help 指令名

比如想知道set指令的作用:

help set

得到结果:

  SET key value [EX seconds] [PX milliseconds] [NX|XX]
  summary: Set the string value of a key
  since: 1.0.0
  group: string

数据类型

redis有五种常用的数据类型:

  • string
  • hash
  • list
  • set
  • sorted_set

下面分别介绍这五种类型。

string

string是redis中最简单的数据类型,也是最常用的数据类型,比如:

set name zhangsan

我们还能一次性保存多个数据:

mset name lisi age 30 gender 1

这样我们就同时设置了三个键值,当然也可以一次性取出多个数据:

mget name age gender

还可以获取字符串长度,比如:

strlen name

需要注意的是当set保存的数据,其键名已经存在的情况下,新的值会覆盖旧的值,redis提供了一种追加方式,以适应更灵活的场景:

append name abc

此时会在key为name字符串后拼接上 abc ,若name不存在,则创建新的数据。

\

若是数据的键值为数字,则redis会提供一些数字特有的功能,但它本质上还是字符串:

set num 1

比如自增操作:

incr num

结果如下:

127.0.0.1:6379> set num 1
OK
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> incr num
(integer) 3
127.0.0.1:6379> incr num
(integer) 4

自减操作:

decr key

结果如下:

127.0.0.1:6379> decr num
(integer) 3
127.0.0.1:6379> decr num
(integer) 2
127.0.0.1:6379> decr num
(integer) 1

默认自增自减操作为加1或减1,若是想设置步长,则:

incrby num 2

结果如下:

127.0.0.1:6379> incrby num 2
(integer) 3
127.0.0.1:6379> incrby num 2
(integer) 5
127.0.0.1:6379> incrby num 2
(integer) 7

自减也是如此:

decrby num 2

步长还支持设置为小数,但incrby是不支持的,我们需要使用incrbyfloat:

incrbyfloat num 0.5

作为缓存数据库,redis的数据都是存储在内存中的,内存十分宝贵,所以我们不应该让一些垃圾数据还残留在redis中浪费资源,为此,我们需要为数据设置它的时效,即:时间一到,就删除对应的数据信息。

\

redis有两种方式设置数据的时效:

setex key seconds value
psetex key milliseconds value

这两种方式的区别在于时间单位不同,第一种设置的是秒,第二种设置的是毫秒,比如:

setex number 10 5

则5秒后,number数据将会被删除。

\

最后是对数据的删除操作:

del name

指定需要删除的键名,则执行该操作后,对应的数据会从redis中删除。

hash

对于一个商城的秒杀业务,其访问量无疑是巨大的,为此,我们应该将一些固定不变的信息提前抽取到redis中,而不是在用户进行秒杀活动的时候再去数据库查询。

比如商品的名称、商品的描述、商品的秒杀价格等等,这些都是在活动即将开始之前就确定好并且不会改变的,我们将其存放到redis中:

 set product:seckill:id:001:name 榨汁机
 set product:seckill:id:001:name 美的榨汁机
 set product:seckill:id:001:price 120 

这是一种较为规范的存储方式,以表名加业务场景加属性名作为数据的键,我们也可以将所有数据封装成一段json数据进行存储:

set product:seckill:id:001 {id:001,name:榨汁机,desc:美的榨汁机,price:120}

然而对于json字符串方式的存储,其弊端是非常明显的,因为若是需要修改商品中的数据,则修改操作就会变得非常麻烦,为此,我们可以使用hash类型来存储。

\

hash类型不同于string,string的特点是一个键对应一个字符串,而hash一个键会对应一组数据,而这组数组也是以键值对的形式进行存储的,对于hash的保存数据和读取数据,只需要在 set 指令的基础上加一个 h 即可:

hset user name zhangsan
hset user age 20

其中 user 为整个hash类型数据的键名,而 name zhangsan 和 age 20 均为hash中的数据,这两个数据也是键值对的形式。

需要注意的是,hset在保存数据时需要一个属性一个属性地进行保存,而不能这样做:

hset user name zhangsan age 20

若是想同时设置多个属性,需要使用 hmset 指令:

hmset user name zhangsan age 20

通过 hgetall 指令可以将属性一次性读取出来:

hgetall user

结果如下:

127.0.0.1:6379> hgetall user
1) "name"
2) "zhangsan"
3) "age"
4) "20"

当然也可以通过 hmget 指令获取所有的属性:

hmget user name age

这种方式相比 hgetall 更加地灵活,也可以读取指定的一个属性:

hget user name
hget user age

删除属性也是如此:

hdel user name
hdel user age

通过 hlen 可以获取hash中属性的数量:

hlen user

通过 hexists 指令可以判断hash中是否存在指定的属性:

hexists user name

存在返回1,不存在返回0。

\

基于hash的特殊结构,redis也提供了hash的特有功能,比如获取hash中的所有属性名和属性值:

hkeys user
hvals user

设置hash中的指定属性进行自增:

hincrby user age 1
hincrbyfloat user age 0.5

hash类型是不支持 hdecrby 和 hdecrbyfloat 的,所以若是想实现自减,可以这么做:

hincrby user age -1

list

list类型适用于存储多个数据,而且能够保持这些数据间的某些顺序。

\

list类型保持数据方式如下:

lpush key value1 [value2] ......
rpush key value1 [value2] ......

其中 lpush 表示从左侧添加, rpush 表示从右侧添加,比如:

lpush nums 1 2 3 4 5

使用 lrange 指令可以读取数据:

lrange nums 0 4

其中 0 4 表示需要读取的索引范围,结果如下:

127.0.0.1:6379> lrange nums 0 4
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"

这说明 lpush 都是从左侧加入,也就是从序列的前面加入数据的,那么相应的:

rpush nums 1 2 3 4 5

rpush 就是从右侧加入,即:从序列的后面加入数据的,其读取顺序应为 1 2 3 4 5 ,结果如下:

127.0.0.1:6379> lrange nums 0 4
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

list类型读取数据的方式如下:

lpop key
rpop key

分别对应从左边获取和从右边获取,若是保存了这样一个数据:

rpush nums 1 2 3 4 5

lpop 的效果如下:

127.0.0.1:6379> lpop nums
"1"

左边的第一个数据 1 就成功被获取了,注意了,通过 lpop 和 rpop 指令获取数据之后,该数据会从list中移除,我们再来试试 rpop 从右边获取,按道理获取到的应该就是 5 :

127.0.0.1:6379> rpop nums
"5"

最后看看list中的数据发生了什么变化:

127.0.0.1:6379> lrange nums 0 4
1) "2"
2) "3"
3) "4"

有时候我们需要移除中间的某个数据,那么 lpop 和 rpop 肯定是无能为力了,为此,我们需要使用 lrem 指令:

lrem nums 1 2

它表示从nums中移除一个数据 2 ,因为list是允许数据重复出现的,所以需要指定移除的数据数量。

\

我们还能通过 lindex 指令获取指定索引上的数据:

lindex nums 0

通过llen 指令获取list的长度,即:数据的个数:

llen nums

list类型也有其特有的功能,它可以在规定时间内获取并移除数据,实现如下:

blpop key1 [key2] timeout
brpop key1 [key2] timeout

比如:

blpop nums nums2 num3 30

它表示从nums、nums2、nums3的左边获取数据,在30秒之内,若是30秒过后获取不到数据,则输出nil;若是在某个时间内获取到了数据,则直接结束,输出内容。

set

set类型同样提供大量数据的存储,但set的优势在于查询速度更快,list类型底层实质上是一个双向链表,我们都知道,链表的查询效率是比较低的,所以若是出于性能的考虑,set绝对是更胜一筹。

\

set类型保持数据的方式如下:

sadd key member1 [member2]

比如:

sadd nums 1 2 3

使用 smembers 指令可以获取到set中的所有数据:

smember nums

删除数据:

srem nums 1 2

表示删除nums中的数据 1 和 2 。

\

获取set的长度:

scard nums

判断set中是否包含指定的数据:

sismember nums 1

set类型比较特别的地方在于它能够进行随机操作,比如随机获取set中指定数量的数据:

srandmember nums 5

它表示从nums中随机获取5个数据,这5个数据获取后并不会消失,仍然存在nums中,相较于接下来的这种方式:

spop nums 5

它表示从nums中随机获取5个数据,但这些数据都会从nums中移除掉。

sorted_set

sorted_set类型支持存储大量的数据,同时还提供这些数据按某种方式进行排序的功能。

\

其保存数据的方式如下:

zadd key score1 member1 [score2 member2]

比如:

zadd scores 95 chinese 98 math 85 english

通过 zrange 指令获取全部数据:

zrange scores 0 -1

携带 withscores 还能够将数据的分数输出:

zrange scores 0 -1 withscores

结果如下:

127.0.0.1:6379> zrange scores 0 -1 withscores
1) "english"
2) "85"
3) "chinese"
4) "95"
5) "math"
6) "98"

通过 zrevrange 指令可以以逆序的方式获取数据:

zrevrange scores 0 -1 withscores

删除数据:

zrem scores chinese math

这里需要注意一点,在保存数据的时候每个数据前都跟着一个数字,比如: 95 chinese ,这个95其实是一个分数,它并不具有特殊的含义,通过该分数,使得sorted_set类型具有一些特殊的功能。

\

首先准备一些数据:

zadd scores 100 zhangsan 90 lisi 95 wangwu

比如查找分数在95以下的数据:

zrangebyscore scores 0 95

其中scores是key, 0 95 是查找范围,结果如下:

127.0.0.1:6379> zrangebyscore scores 0 95
1) "lisi"
2) "wangwu"

它还能够通过 limit 来限定查询的结果,比如查询分数在100以下的前两个数据:

zrangebyscore scores 0 100 limit 0 2

按条件删除数据:

zremrangebyscore scores 0 95

表示删除95分以下的数据,它也支持按照索引删除数据,比如:

zremrangebyrank scores 0 2

它表示删除索引0到索引2的数据。