持续创作,加速成长!这是我参与「掘金日新计划 · 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的数据。