一,数据库管理
1,查看所有数据库:
127.0.0.1:6379> CONFIG GET databases
1) "databases"
2) "16"
为什么这里只显示了数据库个数为16,且并内有显示数据库名?
因为 redis 默认的数据库个数就是十六个,可以查看配置文件:
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
这里的注释就解释了第二个问题,实际上 redis 是根据数据库序列号来确定当前数据库的。
2,切换数据库与查看当前数据库名:
切换数据库时直接指定数据库序号(从0开始)就行。
127.0.0.1:6379> SELECT 3
OK
127.0.0.1:6379[3]> SELECT 0
OK
127.0.0.1:6379>
切换成功后,会在端口号后面显示当前数据库序号。
默认使用第一个数据库(0号),且不显示序号。
3,清空数据库:
清空数据库意味着删除数据库中的所有键值对,需谨慎!
# 清空当前数据库
flushdb
# 清空所有数据库
flushall
使用 Redis 进行应用设计和开发的一个核心概念是数据类型 。
在使用 Redis 进行应用设计和开发时,我们首先应该考虑的是, Redis原生支持的哪种数据类型最适合我们的场景 。然后直接使用 API 发送数据所对应的命令来操作想要操作的目标数据,而无需像在关系数据库中那样,使用 SQL 来操作数据。
这将通过一个Relp应用来学习Redis操作。Relp是一个供用户评论和推荐优秀餐厅、购物中心或其他服务的应用。
二,使用字符串( string )类型
1,SET
命令将一个字符串值关联到一个键
SET key value [EX seconds] [PX milliseconds] [NX|XX]
将字符串值 value 关联到 key 。
如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。
可选参数:
从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:
EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
NX:只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
XX:只在键已经存在时,才对键进行设置操作。
将餐厅名称和地址分别用作键和值:
127.0.0.1:6379> SET "Extreme Pizza" "300 Broadway, New York, NY"
OK
2,GET
命令可以轻松地取回字符串的值
GET key
返回 key 所关联的字符串值。
如果 key 不存在那么返回特殊值 nil 。
假如 key 储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。
127.0.0.1:6379> GET "Extreme Pizza"
"300 Broadway, New York, NY"
3,STRLEN
命令返回字符串的长度
STRLEN key
返回 key 所储存的字符串值的长度。
- 当 key 储存的不是字符串值时,返回一个错误。
获取“Extreme Pizza,,地址的长度。
127.0.0.1:6379> STRLEN "Extreme Pizza"
(integer) 26
4,APPEND
命令可以向一个键的字符串值末尾追加字符串
APPEND key value
向一个键的字符串值末尾追加字符串
如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。
如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。
想更新“Extreme Pizza”的地址。
127.0.0.1:6379> APPEND "Extreme Pizza" " 10011"
(integer) 32
5,SETRANGE
命令可以覆盖字符串值的一部分
SETRANGE key offset value
用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。
不存在的 key 当作空白字符串处理。
SETRANGE 命令会确保字符串足够长以便将 value 设置在指定的偏移量上,如果给定 key原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长,但你设置的offset是10),那么原字符和偏移量之间的空白将用零字节(zerobytes, “\x00” )来填充。
更新“ Extreme Pizza”的地址。
127.0.0.1:6379> SETRANGE "Extreme Pizza" 14 "Washington, DC 20009"
(integer) 34
127.0.0.1:6379> GET "Extreme Pizza"
"300 Broadway, Washington, DC 20009"
6,SETNX
命令仅在键不存在时设置键的值
SETNX key value
将 key 的值设为 value ,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
设置成功,返回 1 。 设置失败,返回 0 。
127.0.0.1:6379> SETNX "Lobster Palace" "437 Main St, Chicago, IL"
(integer) 1
127.0.0.1:6379> SETNX "Extreme Pizza" "300 Broadway, New York, NY 10011"
(integer) 0
7,MSET 和 MGET 命令来一次性地设置和获取多个键的值
MSET key value [key value ...]
同时设置一个或多个 key-value 对。
如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 MSETNX命令:它只会在所有给定 key 都不存在的情况下进行设置操作。
MSET 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key没有改变的情况,不可能发生。
127.0.0.1:6379> MSET "Sakura Sushi" " 123 Ellis St, Chicago, IL" "Green Curry Thai" "456 American Way, Seattle, WA"
OK
MGET key [key ...]
返回所有(一个或多个)给定 key 的值。
- 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。
127.0.0.1:6379> MGET "Sakura Sushi" "Green Curry Thai" "nonexistent"
1) " 123 Ellis St, Chicago, IL"
2) "456 American Way, Seattle, WA"
3) (nil)
#三,使用列表( list )类型
Redis 中的列表更像是数据结构世界中的双向链表。
1,LPUSH
在列表的左端插入
LPUSH key value [value ...]
将一个或多个值 value 插入到列表 key 的表头
如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头: 比如说,对空列表 mylist 执行命令 LPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b和 LPUSH mylist c 三个命令。
如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。
当 key 存在但不是列表类型时,返回一个错误。
使用一个列表来存储用户最喜欢的餐厅 :
127.0.0.1:6379> LPUSH favorite_restaurants " PF Chang's" "Olive Garden"
(integer) 2
2,LRANGE
获取列表中所有值
LRANGE key start stop
返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
- 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
获取列表中所有餐厅的名称:
127.0.0.1:6379> LRANGE favorite_restaurants 0 -1
1) "Olive Garden"
2) " PF Chang's"
3,RPUSH
在列表的右端插入
RPUSH key value [value ...]
将一个或多个值 value 插入到列表 key 的表尾(最右边)。
如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c ,等同于执行命令 RPUSH mylist a 、 RPUSH mylist b、 RPUSH mylist c 。
如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。
当 key 存在但不是列表类型时,返回一个错误。
在列表的右端插入餐厅的名称:
127.0.0.1:6379> RPUSH favorite_restaurants "Outback Steakhouse" "Red Lobster"
(integer) 4
4,LINSERT
将之插入到指定位置前后
LINSERT key BEFORE|AFTER pivot value
将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
当 pivot 不存在于列表 key 时,不执行任何操作。
当 key 不存在时, key 被视为空列表,不执行任何操作。
如果 key 不是列表类型,返回一个错误。
在“PF Chang ’ s”之后插入一个新餐厅的名称:
127.0.0.1:6379> LINSERT favorite_restaurants AFTER " PF Chang's" "Indian Tandoor"
(integer) 5
5,LINDEX
获取指定位置的值
LINDEX key index
返回列表 key 中,下标为 index 的元素。
下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
如果 key 不是列表类型,返回一个错误。
获取列表中位于索引位置 3 处餐厅的名称:
127.0.0.1:6379> LINDEX favorite_restaurants 3
"Outback Steakhouse"
6,LPOP
或 RPOP
从列表中删除一个元素
LPOP key
移除并返回列表 key 的头元素。
127.0.0.1:6379> LRANGE favorite_restaurants 0 -1
1) "Olive Garden"
2) " PF Chang's"
3) "Indian Tandoor"
4) "Outback Steakhouse"
5) "Red Lobster"
127.0.0.1:6379> LPOP favorite_restaurants
"Olive Garden"
127.0.0.1:6379> LPOP favorite_restaurants
" PF Chang's"
127.0.0.1:6379> LRANGE favorite_restaurants 0 -1
1) "Indian Tandoor"
2) "Outback Steakhouse"
3) "Red Lobster"
127.0.0.1:6379> LPOP non_existent
(nil)
RPOP key
移除并返回列表 key 的尾元素
127.0.0.1:6379> RPOP favorite_restaurants
"Red Lobster"
127.0.0.1:6379> LRANGE favorite_restaurants 0 -1
1) "Indian Tandoor"
2) "Outback Steakhouse"
7,LTRIM
命令保留指定范围内的元素
LTRIM key start stop
对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。
下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
当 key 不是列表类型时,返回一个错误。
LTRIM 命令通常和 LPUSH 命令或 RPUSH 命令配合使用,举个例子:
LPUSH log newest_log
LTRIM log 0 99
这个例子模拟了一个日志程序,每次将最新日志 newest_log放到 log 列表中,并且只保留最新的 100 项。
删除最近关门的餐厅:
127.0.0.1:6379> LRANGE favorite_restaurants 0 -1
1) "PF Chang's"
2) "Indian Tandoor"
3) "Outback Steakhouse"
127.0.0.1:6379> LTRIM favorite_restaurants 1 -1
OK
127.0.0.1:6379> LRANGE favorite_restaurants 0 -1
1) "Indian Tandoor"
2) "Outback Steakhouse"
8,LSET
命令设置列表中指定索引位置处元素的值
LSET key index value
将列表 key 下标为 index 的元素的值设置为 value 。
- 当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。
更新餐厅名:
127.0.0.1:6379> LRANGE favorite_restaurants 0 -1
1) "Indian Tandoor"
2) "Outback Steakhouse"
127.0.0.1:6379> LSET favorite_restaurants 1 "Longhorn Steakhouse"
OK
127.0.0.1:6379> LRANGE favorite_restaurants 0 -1
1) "Indian Tandoor"
2) "Longhorn Steakhouse"
9, BLPOP
和 BRPOP
是LPOP 和 RPOP 命令有对应的阻塞版本
三,使用哈希( hash )类型
哈希对于存储对象属性而言是一种完美的数据类型 。
将使用哈希来存储餐厅的信息,例如地址、电话号码和评分等。
1,HMSET
命令来设置哈希键-多个字段-值
HMSET key field value [field value ...]
同时将多个 field-value (域-值)对设置到哈希表 key 中。
此命令会覆盖哈希表中已存在的域。
如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。
设置“ Kyoto Ramen”餐厅的属性信息:
127.0.0.1:6379> HMSET "Kyoto Ramen" "address" "801 Miss ion St, San Jose, CA" "phone" "555-123-6543" "rating" "5.0"
OK
结构如下:
"Kyoto Ramen” = {
”address ”: ” 801 Miss ion St, San Jose, CA”,
”phone ”: ”555-123-6543”,
”rating ”:” 5.0”
}
2,HMGET
命令从一个哈希中获取多个字段对应的值
HMGET key field [field ...]
返回哈希表 key 中,一个或多个给定域的值。
如果给定的域不存在于哈希表,那么返回一个 nil 值。
因为不存在的 key 被当作一个空哈希表来处理,所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。
127.0.0.1:6379> HMGET "Kyoto Ramen" "address" "phone" "rating"
1) "801 Miss ion St, San Jose, CA"
2) "555-123-6543"
3) "5.0"
3,HGET
命令从一个哈希中获取某个字段对应的值
HGET key field
返回哈希表 key 中给定域 field 的值。
127.0.0.1:6379> HGET "Kyoto Ramen" "rating"
"5.0"
4,HEXISTS
命令测试一个哈希中是否存在某个字段
HEXISTS key field
查看哈希表 key 中,给定域 field 是否存在。
127.0.0.1:6379> HEXISTS "Kyoto Ramen" "phone"
(integer) 1
127.0.0.1:6379> HEXISTS "Kyoto Ramen" "hours"
(integer) 0
5,HGETALL
命令获取一个哈希中的所有字段和值
HGETALL key
返回哈希表 key 中,所有的域和值。
- 在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
127.0.0.1:6379> HGETALL "Kyoto Ramen"
1) "address"
2) "801 Miss ion St, San Jose, CA"
3) "phone"
4) "555-123-6543"
5) "rating"
6) "5.0"
6,HSET
命令设置单个字段的值
HSET key field value
将哈希表 key 中的域 field 的值设为 value 。
如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。
如果域 field 已经存在于哈希表中,旧值将被覆盖。
修改餐厅评分并添加开业状态:
127.0.0.1:6379> HSET "Kyoto Ramen" "rating" "4.9"
(integer) 0
127.0.0.1:6379> HSET "Kyoto Ramen" "status" "open"
(integer) 1
127.0.0.1:6379> HMGET "Kyoto Ramen" "rating" "status"
1) "4.9"
2) "open"
7,HOEL
命令从哈希中删除字段
HGET key field
返回哈希表 key 中给定域 field 的值。
127.0.0.1:6379> HDEL "Kyoto Ramen" "address" "phone"
(integer) 2
127.0.0.1:6379> HGETALL "Kyoto Ramen"
1) "rating"
2) "4.9"
3) "status"
4) "open"
8,HSETNX
命令则仅在字段不存在的情况下才设置字段的值
HSETNX key field value
将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在。
若域 field 已经存在,该操作无效。
如果 key 不存在,一个新哈希表被创建并执行 HSETNX 命令。
127.0.0.1:6379> HSETNX "Kyoto Ramen" "phone" "555-555-0001"
(integer) 1
127.0.0.1:6379> HSETNX "Kyoto Ramen" "phone" "555-555-1111"
(integer) 0
9,HSCAN
命令来增量地获取所有字段和值
一个哈希最多能够容纳(2^32)-1个字段 。 如果一个哈希的宇段非常多,那么执行 HGETALL 命令时可能会阻塞 Redis 服务器。 在这种情况下,我们可以使用 HSCAN 命令来增量地获取所有字段和值.
该命令会增量地迭代遍历元素,从而不会造成服务器阻塞 。 HSCAN 命令是一种基于指针的迭代器,因此我们需要在每次调用命令时指定一个游标(从 0 开始)。 当一次 HSCAN 运行结束后, Redis 将返回一个元素列表以及一个新的游标,这个游标可以用于下一次迭代。
HSCAN key cursor [MATCH pattern] [COUNT number]
- 选项 MATCH 可以用来匹配满足指定 G lob 表达式的字段 。 选项 COUNT 用来说明在每次迭代中应该返回多少个元素 。
但是,这个选项仅仅是一种参考,Redis 并不保证返回的元素数量就是 COUNT个,COUNT 的默认值是 10 。
设我们有一个非常大的哈希,其中有数百万个甚至更多的字段。 下面,让我们使用 HSCAN
来遍历包含关键字 garden 的字段:
127.0.0.7:6379> HSCAN restaurant_ratings O MATCH *garden*
1)"309"
2) 1)"panda garden"
2)"3.9"
3)"chang’s garden"
4)"4.5"
5)"rice garden"
6)"4 .8"
使用由服务器返回的新游标 309 来进行一次新的迭代:\
127.0.0.7:6379> HSCAN restaurant_ratings 309 MATCH *garden*
1)"0"
2) 1)"szechuwan garden"
2)"4.9"
3)"garden wok restaurant"
4)"4.7"
5)"win garden"
6)"4.0"
7)"east garden restaurant"
8)"4 6"
四,使用集合( set )类型
集合类型是由唯一 、无序对象组成的集合( collection ) 。 它经常用于测试某个成员是否在集合中 、 重复项删除和集合运算(求并、交、差集)。
1,SADD 命令将元素插入集合
SADD key member [member ...]
将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
当 key 不是集合类型时,返回一个错误。
给”Original Buffalo Wings”餐厅添加标签:
127.0.0.1:6379> SADD "Original Buffalo Wings" "affordable" "spicy" "busy" "great taste"
(integer) 4
2,,SISMEMBER
命令测试一个元素是否位于集合中
SISMEMBER key member
判断 member 元素是否集合 key 的成员。
- 如果 member 元素是集合的成员,返回 1 。 如果 member 元素不是集合的成员,或 key 不存在,返回 0 。
127.0.0.1:6379> SISMEMBER "Original Buffalo Wings" "busy"
(integer) 1
127.0.0.1:6379> SISMEMBER "Original Buffalo Wings" "costly"
(integer) 0
3,SREM
命令从集合中删除元素
SREM key member [member ...]
移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
- 当 key 不是集合类型,返回一个错误。
餐厅的标签中删除“busy”和”spicy”:
127.0.0.1:6379> SREM "Original Buffalo Wings" "busy" "spicy"
(integer) 2
127.0.0.1:6379> SISMEMBER "Original Buffalo Wings" "busy"
(integer) 0
127.0.0.1:6379> SISMEMBER "Original Buffalo Wings" "spicy"
(integer) 0
4,SCARD
命令获取集合中成员的数量
SCARD key
返回集合 key 的基数(集合中元素的数量)。
127.0.0.1:6379> SCARD "Original Buffalo Wings"
(integer) 2
5,SMEMBERS
命令列出集合中的所有元素
SMEMBERS key
返回集合 key 中的所有成员。
- 不存在的 key 被视为空集合。
127.0.0.1:6379> SMEMBERS "Original Buffalo Wings"
1) "great taste"
2) "affordable"
- 但是,与我们在使用哈希类型中所提到的
HGETALL
类似,在一个大的集合中使用SMEMBERS
命令可能会阻塞服务器。 因此,我们并不推荐使用SMEMBERS
命令,而是应该使用SSCAN
命令 。SSCAN
与我们在使用哈希类型中的HSCAN
命令的用法非常类似。
6,集合运算
SUNION
和 SUNIONSTORE
用于计算并集,
SINTER
和 SINTERSTORE
用于计算交集,
SDIFF
和 SDIFFSTORE
用于计算差集 。
不带 STORE
后缀的命令只返回相应操作的结果集合,而带 STORE
后缀的命令则会将结果存储到一个指定的键中 。
给另一家餐厅”Big Bear Wings”添加标签 ,然后获取”Original Buffalo Wings ”和” Big Bear Wings ”餐厅共有的标签:
127.0.0.1:6379> SMEMBERS "Original Buffalo Wings"
1) "great taste"
2) "affordable"
127.0.0.1:6379> SADD "Big Bear Wings" "affordable" "spacious" "great music"
(integer) 3
127.0.0.1:6379> SINTER "Original Buffalo Wings" "Big Bear Wings"
1) "affordable"
127.0.0.1:6379> SINTERSTORE "common_tags" "Original Buffalo Wings" "Big Bear Wings"
(integer) 1
127.0.0.1:6379> SMEMBERS "common_tags"
1) "affordable"
五,使用有序集合( sorted set )类型
单词“ Sorted”意味着这种集合中的每个元素都拥有一个可用于排序的权重,并且我们可以按顺序从集合中获取元素,在某些需要一直保持数据有序的场景中,使用这种原生的有序特性是很方便的 。
1,ZADD
命令插入成员与score
ZADD key score member [[score member] [score member] ...]
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该member 在正确的位置上。
score 值可以是整数值或双精度浮点数。
如果 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
当 key 存在但不是有序集类型时,返回一个错误。
返回值:被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
- 在
ZADD
命令中使用NX
选项,能够实现在不更新已存在成员的情况下只添加新的成员 - 选项 xx 允许我们在不向集合中增加新元素的情况下更新集合(即只更新存在的成员而不添加新成员)
- 多个不同的成员可能具有相同的权重。在这种情况下,Redis将按照字典顺序进行排序
将点评数和每个餐厅的名字放入一个有序集合中:
127.0.0.1:6379> ZADD ranking:restaurants 100 "Olive Garden" 23 "PF Changs" 34 "Outback Steakhouse" 45 "Red Lobster" 88 "Longhorn Steakhouse"
(integer) 5
2,ZREVRANGE
命令获取指定范围内的成员
ZREVRANGE key start stop [WITHSCORES]
返回有序集 key 中,指定区间内的成员。
- 其中成员的位置按 score 值递减(从大到小)来排列。 具有相同 score 值的成员按字典序的逆序(reverse lexicographical order)排列。 除了成员按 score 值递减的次序排列这一点外, ZREVRANGE 命令的其他方面和 ZRANGE 命令一样。
获取这个评分排名:
127.0.0.1:6379> ZREVRANGE ranking:restaurants 0 -1 WITHSCORES
1) "Olive Garden"
2) "100"
3) "Longhorn Steakhouse"
4) "88"
5) "Red Lobster"
6) "45"
7) "Outback Steakhouse"
8) "34"
9) "PF Changs"
10) "23"
127.0.0.1:6379> ZREVRANGE ranking:restaurants 0 -1
1) "Olive Garden"
2) "Longhorn Steakhouse"
3) "Red Lobster"
4) "Outback Steakhouse"
5) "PF Changs"
3,ZINCRBY
命令为指定成员的score增加数值
ZINCRBY key increment member
为有序集 key 的成员 member 的 score 值加上增量 increment 。
可以通过传递一个负数值 increment ,让 score 减去相应的值,比如 ZINCRBY key -5 member ,就是让
member 的 score 值减去 5 。当 key 不存在,或 member 不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD
key increment member 。当 key 不是有序集类型时,返回一个错误。
score 值可以是整数值或双精度浮点数。
如果 Relp 中的某个用户点了赞,对餐厅的投票数加一 :
127.0.0.1:6379> ZINCRBY ranking:restaurants 1 "Red Lobster"
"46"
4,ZREVRANK命令据score获取成员排名
ZREVRANK key member
返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。
排名以 0 为底,也就是说, score 值最大的成员排名为 0 。
使用 ZRANK 命令可以获得成员按 score 值递增(从小到大)排列的排名。
浏览某个特定餐厅的排名:
127.0.0.1:6379> ZREVRANK ranking:restaurants "Red Lobster"
(integer) 2
5,ZSCORE
命令获取score
ZSCORE key member
返回有序集 key 中,成员 member 的 score 值。
- 如果 member 元素不是有序集 key 的成员,或 key 不存在,返回 null。
浏览某个特定餐厅的投票数:
127.0.0.1:6379> ZSCORE ranking:restaurants "Olive Garden"
"100"
6,ZUNIONSTORE
命令合并两个sorted set
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
计算给定的一个或多个有序集的并集,其中给定key
的数量必须以numkeys
参数指定,并将该并集(结果集)储存到destination
。
默认情况下,结果集中某个成员的
score
值是所有给定集下该成员score
值之和 。
WEIGHTS
:可以为 每个给定有序集分别指定一个乘法因子(multiplication factor
),每个给定有序集的所有成员的score
值在传递给聚合函数(aggregation function
)之前都要先乘以该有序集的因子。如果没有指定该选项,乘法因子默认设置为 1 。
AGGREGATE
:可以指定并集的结果集的聚合方式。默认使用的参数SUM
,可以将所有集合中某个成员的score
值之和作为结果集中该成员的score
值;使用参数MIN
,可以将所有集合中某个成员的最小score
值作为结果集中该成员的score
值;而参数MAX
则是将所有集合中某个成员的最大score
值作为结果集中该成员的score
值。
127.0.0.1:6379> ZADD ranking2:restaurants 50 "Olive Garden" 33 "PF Changs" 55 "Outback Steakhouse" 190 "Kung Pao House"
(integer) 4
127.0.0.1:6379> ZUNIONSTORE totalranking 2 ranking:restaurants ranking2:restaurants WEIGHTS 1 2
(integer) 6
127.0.0.1:6379> ZREVRANGE totalranking 0 -1 WITHSCORES
1) "Kung Pao House"
2) "380"
3) "Olive Garden"
4) "200"
5) "Outback Steakhouse"
6) "144"
7) "PF Changs"
8) "89"
9) "Longhorn Steakhouse"
10) "88"
11) "Red Lobster"
12) "46"
六,使用 Hyperloglog 类型
在日常的各种数据处理场景中,“唯一计数”是一项常见的任务 。 在 Redis 中,虽然我们可以使用集合来进行唯一计数;但是,当数据量增大到上千万时,就需要考虑内存消耗和性能下降问题了。
如果我们不需要获取数据集的内容,而只是想得到不同值的个数,那么就可以使用 HyperLogLog(HLL)
数据类型来优化使用集合类型时存在的内存和性能问题。
1,PFADD
命令将元素加入到一个 HyperLogLog 类型的key
PFADD key element [element ...]
计算 Relp 中到访名为 Olive Garden 的餐厅的不同客户数:
127.0.0.1:6379> PFADD "Counting:Olive Garden" "0000123"
(integer) 1
127.0.0.1:6379> PFADD "Counting:Olive Garden" "0023992"
(integer) 1
2,PFCOUNT命令统计HyperLogLog 类型的key中元素个数
PFCOUNT key [key ...]
返回给定 HyperLogLog 的基数估算值。
127.0.0.1:6379> PFCOUNT "Counting:Olive Garden"
(integer) 2
3,PFMERGE 命令合并多个HyperLogLog 类型的key
PFMERGE destkey sourcekey [sourcekey ...]
将多个 HyperLogLog 合并为一个HyperLogLog ,合并后的 HyperLogLog 的基数估算值是通过对所有 给定 HyperLogLog 进行并集计算得出的。
如果想要展示 Olive Garden 在一个星期中的独立访客数,并将其作为每周流行度的标志 。 那么,我们可以每天生成一个 HLL
,然后用 PFMERGE
命令把这 7 天的数据合并为一个:
127.0.0.1:6379> PFADD "Counting:Olive Garden:20170903" "0023992" "0023991" "0045992"
(integer) 1
127.0.0.1:6379> PFADD "Counting:Olive Garden:20170904" "0023992" "0023991" "0045992"
(integer) 1
127.0.0.1:6379> PFADD "Counting:Olive Garden:20170905" "0024492" "0023211" "0045292"
(integer) 1
127.0.0.1:6379> PFADD "Counting:Olive Garden:20170906" "0023999" "0063991" "0045922"
(integer) 1
127.0.0.1:6379> PFADD "Counting:Olive Garden:20170907" "0023292" "0023991" "0045921"
(integer) 1
127.0.0.1:6379> PFADD "Counting:Olive Garden:20170908" "0043282" "0023984" "0045092"
(integer) 1
127.0.0.1:6379> PFADD "Counting:Olive Garden:20170909" "0023992" "0023991" "0045992"
(integer) 1
127.0.0.1:6379> PFCOUNT "Counting:Olive Garden:20170903week"
(integer) 14
七,使用 Geo 类型
随着移动端设备机的不断普及, 基于地理位置的服务变得越来越受欢迎。 Redis 从 3.2 版本开始正式引人了Geo
相关的 API ,用于支持存储和查询这些地理位置相关场景中的坐标 。
1,GEOADD命令设置地点经纬度数据
GEOADD location-set longitude latitude member [longitude latitude member ...]
把位于加州的五家餐厅增加到名为 restaurants:CA 的 Geo 集合中:
127.0.0.1:6379> GEOADD restaurants:CA -121.896321 37.916750 "Olive Garden" -117.910937 33.804047 "P.F. Changs" -118.508020 34.453276 "Outback Steakhouse" -119.152439 34.264558 "Red Lobster" -122.276909 39.458300 "Longhorn Charcoal Pit"
(integer) 5
2,GEOPOS
命令从 Geo 集合中获取指定成员的坐标:
127.0.0.1:6379> GEOPOS restaurants:CA "Red Lobster"
1) 1) "-119.15243893861771"
2) "34.264557072833789"
3,GEODIST
命令获取两个地理位置的距离
GEODIST location-set location-x location-y [unit]
其中 unit 参数是距离单位,可选填
- m 表示单位为米。
- km 表示单位为千米。
- mi 表示单位为英里。
- ft 表示单位为英尺。
127.0.0.1:6379> GEODIST restaurants:CA "P.F. Changs" "Outback Steakhouse" km
"90.7557"
4,GEORADIUS命令获取指定范围内的坐标点
GEORADIUS location-set longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]
- radius表示范围距离,距离单位是m|km|ft|mi
可选参数:
- WITHCOORD:传入WITHCOORD参数,则返回结果会带上匹配位置的经纬度。
- WITHDIST:传入WITHDIST参数,则返回结果会带上匹配位置与给定地理位置的距离。
- ASC|DESC:默认结果是未排序的,传入ASC为从近到远排序,传入DESC为从远到近排序。
- WITHHASH:传入WITHHASH参数,则返回结果会带上匹配位置的hash值。 COUNT
- count:传入COUNT参数,可以返回指定数量的结果
假设读者位于在 Mount Diablo State Park, 其经/纬度是-121.923170/37.878506,如果读者想知道距当前位置 skrn 以内的餐厅,那么可以使用:
127.0.0.1:6379> GEORADIUS restaurants:CA -121.923170 37.878506 5 km
1) "Olive Garden"
5,GEORADIUSBYMEMBER
命令搜索 Geo 集合中指定范围内的坐标点
搜索 Geo 集合中距离“Outback Steakhouse,距离小于 100 km 的餐厅:
127.0.0.1:6379> GEORADIUSBYMEMBER restaurants:CA "Outback Steakhouse" 100 km
1) "Red Lobster"
2) "Outback Steakhouse"
3) "P.F. Changs"
Geo 集合实际上被存储为一个有序集合( Redis 中的 zset ),因此有序集合支持的所有命令都可以用于 Geo 数据类型 。
八,键管理
Redis 中的数据都是由键值对组成的 。 因此,管理键是应用程序开发和 Redis 管理的另一个基本知识。
1,DBSIZE
命令获取所有键的个数
127.0.0.1:6379> DBSIZE
(integer) 50025
2, KEYS
命令或SCAN
命令获取所有键
在 Redis 中的一个命令执行过程期间 ,所有服务器接收到的其他命令都必须等待被处理。 因此,对于生产环境的性能来说,调用KEYS
命令是一个危险的操作。 对于这个问题,可以使用此前案例中所提到的 SCAN
类命令,如SCAN
或 SSCAN
,以在不阻塞服务器的情况下在 Redis 服务器上遍历键 。
采用全量式KEYS
命令:
KEYS pattern
查找所有符合给定模式 pattern 的 key :
- KEYS * 匹配数据库中所有 key 。
- KEYS h?llo 匹配 hello 、hallo 和 hxllo 等。
- KEYS h*llo 匹配 hllo 和 heeeeello 等。
- KEYS h[ae]llo 匹配 hello 和 hallo。
- 特殊符号用 \ 隔开。
127.0.0.1:6379> KEYS *
......
50023) "user_agent:2789"
50024) "simple_registration:579"
50025) "user_agent:8587"
(0.73s)
采用增量式的SCAN
命令:
127.0.0.1:6379> scan 0
1) "18432"
2) 1) "company:3945"
2) "detailed_registration:508"
3) "customer:5211"
4) "detailed_registration:659"
5) "customer:6139"
6) "company:1640"
7) "simple_registration:2049"
8) "company:3892"
9) "user_agent:9178"
10) "simple_registration:6059"
127.0.0.1:6379> SCAN 18432
1) "14336"
2) 1) "company:1542"
2) "customer:4306"
3) "user_agent:6220"
4) "company:8466"
5) "customer:2375"
6) "customer:7657"
7) "detailed_registration:1230"
8) "customer:4381"
9) "customer:5321"
10) "detailed_registration:2876"
11) "simple_registration:5163"
3,EXISTS
命令判断一个键是否存在
EXISTS key
检查给定 key 是否存在。
- 若 key 存在,返回 1 ,否则返回 0 。
127.0.0.1:6379> EXISTS "simple_registration:7681"
(integer) 1
127.0.0.1:6379> EXISTS "simple_registration:99999"
(integer) 0
4,TYPE
命令获取键的数据类型
TYPE key 返回 key 所储存的值的类型
none (key不存在)
string (字符串)
list (列表)
set (集合)
zset (有序集)
hash (哈希表)
127.0.0.1:6379> TYPE "company:3859"
hash
5,RENAME
或 RENAMENX
命令重命名一个键:
RENAME key newkey
将 key 改名为 newkey 。
当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。
当 newkey 已经存在时, RENAME 命令将覆盖旧值。
RENAME key newkey
将 key 改名为 newkey 。
- 当且仅当 newkey 不存在时,将 key 改名为 newkey 。 修改成功时,返回 1 。
当 key 不存在时,返回一个错误。
127.0.0.1:6379> EXISTS "customer:6591"
(integer) 1
127.0.0.1:6379> EXISTS "customer:659l:renamed"
(integer) 0
127.0.0.1:6379> RENAME "customer:6591" "customer:659l:renamed"
OK
127.0.0.1:6379> EXISTS "customer:6591"
(integer) 0
127.0.0.1:6379> EXISTS "customer:659l:renamed"
(integer) 1
RENAME
会在目标键己存在时将其删除 。 这个 DEL
操作可能导致高延迟 。因此,重命名操作的最佳实践是,如果目标键已存在则先对其执行UNLINK
然后再进行重命名 。
6,DEL
命令或 UNLINK
命令删除键
DEL key [key ...]
删除给定的一个或多个 key 。
- 不存在的 key 会被忽略。 被删除 key 的数量。
127.0.0.1:6379> DEL "detailed_registration:l665" "simple_registration:6411" "user_agent:l683 "
(integer) 1
UNLINK
在 Redis 4.0 以上版本引人,主要用于执行大KEY的异步删除.
127.0.0.1:6379> UNLINK "company:1664"
(integer) 1
应该对 DEL
命令额外留意。 如果要删除的键是字符串以外的数据类型 ,那么当键中的元素数量很大时就可能会遭遇服务器延迟 。 为了避免这种灾难,应该使用 UNLINK
替代 。 UNLINK
会在另一个线程而不是主事件循环线程中执行删除操作,因而不会阻塞事件的处理。
7,超时设置
为键设置超时时间(意味着客户端访问服务器的这个键值时,会先判断是否过期):
# 设置超时时间,单位秒。
EXPIRE key seconds
# 剩余过期秒数,返回-1表示没有设置过过期时间,对于不存在的key,返回-2
TTL key
# 持久化,永不过期。
PERSIST key
8,key的设计规范
key的一个格式约定:
1: 第1段放置表名作为前缀,如,tag:
2: 第2段放置用于区分key的字段——对应mysql中的主键的列名,如userid
3: 第3段放置主键值,如2,3,4…, a , b ,c 4:
4: 第4段放置要存储的列名
举个例子:将用户表转为键值对存储。
userid username password email
9 lisi 1111111 lisi@163.com
set user:userid:9:username lisi
set user:userid:9:password 111111
set user:userid:9:email lisi@163.com
然后查看某个用户的所有信息:
keys user:userid:9*
更多键管理命令与原理请参考官方文档。
九,用python实现一个redis小项目
这是《redis in action》中的一个小项目,旨在进一步理解对不同数据类型的使用。
描述:构建一个文章投票网站——如果一篇文章获得了至少200张支持票(up vote),那么网站就认为这篇文章是一篇有趣的文章,就是把文章放到文章列表前100位至少一天;暂时不提供投反对票(down vote)的功能。
存储文章信息:对于网站里的每篇文章,需要有文章的标题、指向文章的网址、发布文章的用户、文章的发布时间、文章得到的投票数量等信息。
实现:使用hash数据类型
时间榜:存储文章的发布时间,用于后续的评分计算
评分功能:为了产生一个能够随着时间流逝而不断减少的评分,程序需要根据文章的发布时间和当前时间来计算文章的评分。为了尽量节约内存,我们规定当一篇文章发布期满一周之后,用户将不能再对它进行投票,文章评分将被固定。
实现:使用zset类型
评分榜:存储文章的评分,
补充:为了防止用户对同一篇文章进行多次投票,网站需要为每篇文章记录一个已投票用户名单。文章的评分被固定下来后,而记录文章已投票用户名单的集合也会被删除。
实现:使用set类型
发布文章:
获取文章:
文章投票:
在这里插入代码片
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/98127.html