继上篇搭建完redis之后,现在开始对redis中的基本操作进行讲解。
通过输入
redis-cli -h
可看到:
Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
-h <hostname> Server hostname (default: 127.0.0.1).
-p <port> Server port (default: 6379).
-s <socket> Server socket (overrides hostname and port).
-a <password> Password to use when connecting to the server.
You can also use the REDISCLI_AUTH environment
variable to pass this password more safely
(if both are used, this argument takes predecence).
-u <uri> Server URI.
-r <repeat> Execute specified command N times.
-i <interval> When -r is used, waits <interval> seconds per command.
It is possible to specify sub-second times like -i 0.1.
-n <db> Database number.
-x Read last argument from STDIN.
-d <delimiter> Multi-bulk delimiter in for raw formatting (default: \n).
-c Enable cluster mode (follow -ASK and -MOVED redirections).
--raw Use raw formatting for replies (default when STDOUT is
not a tty).
--no-raw Force formatted output even when STDOUT is not a tty.
--csv Output in CSV format.
--stat Print rolling stats about server: mem, clients, ...
--latency Enter a special mode continuously sampling latency.
If you use this mode in an interactive session it runs
forever displaying real-time stats. Otherwise if --raw or
--csv is specified, or if you redirect the output to a non
TTY, it samples the latency for 1 second (you can use
-i to change the interval), then produces a single output
and exits.
--latency-history Like --latency but tracking latency changes over time.
Default time interval is 15 sec. Change it using -i.
--latency-dist Shows latency as a spectrum, requires xterm 256 colors.
Default time interval is 1 sec. Change it using -i.
--lru-test <keys> Simulate a cache workload with an 80-20 distribution.
--replica Simulate a replica showing commands received from the master.
--rdb <filename> Transfer an RDB dump from remote server to local file.
--pipe Transfer raw Redis protocol from stdin to server.
--pipe-timeout <n> In --pipe mode, abort with error if after sending all data.
no reply is received within <n> seconds.
Default timeout: 30. Use 0 to wait forever.
--bigkeys Sample Redis keys looking for keys with many elements (complexity).
--memkeys Sample Redis keys looking for keys consuming a lot of memory.
--memkeys-samples <n> Sample Redis keys looking for keys consuming a lot of memory.
And define number of key elements to sample
--hotkeys Sample Redis keys looking for hot keys.
only works when maxmemory-policy is *lfu.
--scan List all keys using the SCAN command.
--pattern <pat> Useful with --scan to specify a SCAN pattern.
--intrinsic-latency <sec> Run a test to measure intrinsic system latency.
The test will run for the specified amount of seconds.
--eval <file> Send an EVAL command using the Lua script at <file>.
--ldb Used with --eval enable the Redis Lua debugger.
--ldb-sync-mode Like --ldb but uses the synchronous Lua debugger, in
this mode the server is blocked and script changes are
not rolled back from the server memory.
--cluster <command> [args...] [opts...]
Cluster Manager command and arguments (see below).
--verbose Verbose mode.
--no-auth-warning Don't show warning message when using password on command
line interface.
--help Output this help and exit.
--version Output version and exit.
Cluster Manager Commands:
Use --cluster help to list all available cluster manager commands.
Examples:
cat /etc/passwd | redis-cli -x set mypasswd
redis-cli get mypasswd
redis-cli -r 100 lpush mylist x
redis-cli -r 100 -i 1 info | grep used_memory_human:
redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3
redis-cli --scan --pattern '*:12345*'
(Note: when using --eval the comma separates KEYS[] from ARGV[] items)
When no command is given, redis-cli starts in interactive mode.
Type "help" in interactive mode for information on available commands
and settings.
可以看到有许许多多的指令,其中有一个-n的参数,看描述代表指定连接的数据库,redis默认有16个库,0-15号,可自行选择连接。
#通过输入此命令,即可连接6号库
redis-cli -n 6
#不指定,默认0号库
redis-cli
此时映入眼帘的就是客户端的交互式界面。
那有什么东西呢?不懂就敲
help
127.0.0.1:6379[6]> help
redis-cli 5.0.5
To get help about Redis commands type:
"help @<group>" to get a list of commands in <group>
"help <command>" for help on <command>
"help <tab>" to get a list of possible help topics
"quit" to exit
To set redis-cli preferences:
":set hints" enable online hints
":set nohints" disable online hints
Set your preferences in ~/.redisclirc
可以看到,提示我们可以通过敲入@ 然后按tab键,发现会自动联想很多
例如:
help @generic
可以看到通用命令列表:
DEL key [key ...]
summary: Delete a key
since: 1.0.0
DUMP key
summary: Return a serialized version of the value stored at the specified key.
since: 2.6.0
EXISTS key [key ...]
summary: Determine if a key exists
since: 1.0.0
EXPIRE key seconds
summary: Set a key's time to live in seconds
since: 1.0.0
EXPIREAT key timestamp
summary: Set the expiration for a key as a UNIX timestamp
since: 1.2.0
KEYS pattern
summary: Find all keys matching the given pattern
since: 1.0.0
MIGRATE host port key| destination-db timeout [COPY] [REPLACE] [KEYS key]
summary: Atomically transfer a key from a Redis instance to another one.
since: 2.6.0
MOVE key db
summary: Move a key to another database
since: 1.0.0
OBJECT subcommand [arguments [arguments ...]]
summary: Inspect the internals of Redis objects
since: 2.2.3
PERSIST key
summary: Remove the expiration from a key
since: 2.2.0
PEXPIRE key milliseconds
summary: Set a key's time to live in milliseconds
since: 2.6.0
PEXPIREAT key milliseconds-timestamp
summary: Set the expiration for a key as a UNIX timestamp specified in milliseconds
since: 2.6.0
PTTL key
summary: Get the time to live for a key in milliseconds
since: 2.6.0
RANDOMKEY -
summary: Return a random key from the keyspace
since: 1.0.0
RENAME key newkey
summary: Rename a key
since: 1.0.0
RENAMENX key newkey
summary: Rename a key, only if the new key does not exist
since: 1.0.0
RESTORE key ttl serialized-value [REPLACE]
summary: Create a key using the provided serialized value, previously obtained using DUMP.
since: 2.6.0
SCAN cursor [MATCH pattern] [COUNT count]
summary: Incrementally iterate the keys space
since: 2.8.0
SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]
summary: Sort the elements in a list, set or sorted set
since: 1.0.0
TOUCH key [key ...]
summary: Alters the last access time of a key(s). Returns the number of existing keys specified.
since: 3.2.1
TTL key
summary: Get the time to live for a key
since: 1.0.0
TYPE key
summary: Determine the type stored at key
since: 1.0.0
UNLINK key [key ...]
summary: Delete a key asynchronously in another thread. Otherwise it is just as DEL, but non blocking.
since: 4.0.0
WAIT numreplicas timeout
summary: Wait for the synchronous replication of all the write commands sent in the context of the current connection
since: 3.0.0
POST ...options...
summary: Help not available
since: not known
SUBSTR key arg arg
summary: Help not available
since: not known
REPLCONF ...options...
summary: Help not available
since: not known
PFSELFTEST
summary: Help not available
since: not known
HOST: ...options...
summary: Help not available
since: not known
ASKING
summary: Help not available
since: not known
LATENCY arg ...options...
summary: Help not available
since: not known
RESTORE-ASKING key arg arg ...options...
summary: Help not available
since: not known
PSYNC arg arg
summary: Help not available
since: not known
MODULE arg ...options...
summary: Help not available
since: not known
PFDEBUG arg arg ...options...
summary: Help not available
since: not known
XSETID key arg
summary: Help not available
since: not known
GEORADIUS_RO key arg arg arg arg ...options...
summary: Help not available
since: not known
GEORADIUSBYMEMBER_RO key arg arg arg ...options...
summary: Help not available
since: not known
LOLWUT ...options...
summary: Help not available
since: not known
例如:
keys * #可以得到当前库的所有key
Redis中的Key
redis是key,value型的内存数据库,value的类型十分的丰富,而在此之前,我们先说一下key
key可以看成是一个对象类型,其中有3个主要的属性标识:
type:标识着当前value的类型 ,有了它可以快速判断当前value类型是否可以调用某个操作,而不需要等到计算时再抛异常
encoding:标识value当前的编码,也可用于快速判断,例如string类型的value可根据此值快速判断是否可以进行字符串或者数值的操作
length:一次计算出value的长度后,将其保存下来,而无需每次都进行计算
type key名称 #访问某个key的value的类型
OBJECT encoding key名称 #访问某个key的value的编码
length通过各类型都有对应的获取长度的方法。
接下来对各个value类型进行一一说明
string
string是redis中最直接最简单的类型,至少,看似是这样的,但其实它内部也可以细分为三种类型:
1、字符串
2、数值
3、bitmap
针对每种类型,都有对应的操作
输入
help @string
可以看到string类型value的所有操作方法
127.0.0.1:6379[6]> help @string
APPEND key value
summary: Append a value to a key
since: 2.0.0
BITCOUNT key [start end]
summary: Count set bits in a string
since: 2.6.0
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
summary: Perform arbitrary bitfield integer operations on strings
since: 3.2.0
BITOP operation destkey key [key ...]
summary: Perform bitwise operations between strings
since: 2.6.0
BITPOS key bit [start] [end]
summary: Find first bit set or clear in a string
since: 2.8.7
DECR key
summary: Decrement the integer value of a key by one
since: 1.0.0
DECRBY key decrement
summary: Decrement the integer value of a key by the given number
since: 1.0.0
GET key
summary: Get the value of a key
since: 1.0.0
GETBIT key offset
summary: Returns the bit value at offset in the string value stored at key
since: 2.2.0
GETRANGE key start end
summary: Get a substring of the string stored at a key
since: 2.4.0
GETSET key value
summary: Set the string value of a key and return its old value
since: 1.0.0
INCR key
summary: Increment the integer value of a key by one
since: 1.0.0
INCRBY key increment
summary: Increment the integer value of a key by the given amount
since: 1.0.0
INCRBYFLOAT key increment
summary: Increment the float value of a key by the given amount
since: 2.6.0
MGET key [key ...]
summary: Get the values of all the given keys
since: 1.0.0
MSET key value [key value ...]
summary: Set multiple keys to multiple values
since: 1.0.1
MSETNX key value [key value ...]
summary: Set multiple keys to multiple values, only if none of the keys exist
since: 1.0.1
PSETEX key milliseconds value
summary: Set the value and expiration in milliseconds of a key
since: 2.6.0
SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
summary: Set the string value of a key
since: 1.0.0
SETBIT key offset value
summary: Sets or clears the bit at offset in the string value stored at key
since: 2.2.0
SETEX key seconds value
summary: Set the value and expiration of a key
since: 2.0.0
SETNX key value
summary: Set the value of a key, only if the key does not exist
since: 1.0.0
SETRANGE key offset value
summary: Overwrite part of a string at key starting at the specified offset
since: 2.2.0
STRLEN key
summary: Get the length of the value stored in a key
since: 2.2.0
如上所述,这里string类型的value方法其实可以分为三类:
1、string
set
get
append
setrange
getrange
strlen
做个试验,2个key,1个放数值,1个放字母,此时看key上的encoding有什么不同?
127.0.0.1:6379[6]> set k1 a
OK
127.0.0.1:6379[6]> set k2 123
OK
127.0.0.1:6379[6]> OBJECT encoding k1
"embstr"
127.0.0.1:6379[6]> OBJECT encoding k2
"int"
发现,encoding有所不同,实际上,虽然存储的都是字符串,但redis对此做了优化,标识字符串里的内容到底是数值还是非数值,
进而可以有一些用于专属于数值或字符的操作,而是否能够使用,无需每次都去判断一下,只需要看这个值就能快速判断了。
继续操作,在k2上追加asd,在看encoding
127.0.0.1:6379[6]> APPEND k2 asd
(integer) 6
127.0.0.1:6379[6]> OBJECT encoding k2
"raw"
发现变成了raw。 raw又是啥呢? 后续解答。
Redis的存储与显示
redis的底层存储实际上是字节数组,因此是二进制安全的。
默认情况下,客户端只能显示ASCII码的value,而非ASCII的会转换成16进制进行显示。
127.0.0.1:6379[6]> set k3 哈哈
OK
127.0.0.1:6379[6]> get k3
"\xe5\x93\x88\xe5\x93\x88"
当然可以手动指定以当前客户端连接编码进行解码,只需要在连接的时候这样输入:
[root@dream01 ~]# redis-cli --raw
127.0.0.1:6379> get k3
哈哈
发现结果就是可以显示中文了。
2、数值
INCR key
summary: Increment the integer value of a key by one
since: 1.0.0
INCRBY key increment
summary: Increment the integer value of a key by the given amount #如果想要的不是递增而是递减怎么办? increment为负数即可
since: 1.0.0
INCRBYFLOAT key increment
summary: Increment the float value of a key by the given amount
since: 2.6.0
应用场景:
抢购,秒杀,详情页,点赞,评论规避并发下,对数据库的事务操作完全由redis内存操作代替
3、bitmap(最有价值的类型)
要想清楚bitmap的使用,需要先了解一下它的存储结构
如图,1个字节有8位,从左到右位的索引从0开始。
举例说明,比如我们想要存一个"B"进去,B的ascii是42,它的16进制表现为 0010 0010,参照上图,只要在索引为1和索引为6的地方标识位置为1就可以了。
127.0.0.1:6379> SETBIT bkey 1 1
(integer) 0
127.0.0.1:6379> SETBIT bkey 6 1
(integer) 0
127.0.0.1:6379> get bkey
"B"
在指定key的指定的offset下设置位值
SETBIT key offset value
获取指定key在指定字节范围内找到的第一个指定的bit值的offset
BITPOS key bit [start] [end]
获取指定key在指定字节范围内的为1的位总个数
BITCOUNT key [start end]
将若干个key进行指定操作(与,或,非等) ,将得到的结果放入destkey指定的key
BITOP operation destkey key [key ...]
应用场景:
1、有一个用户系统,需要统计用户登录天数,且选取天数窗口随机
如果按照传统办法来说,我们可以选择使用mysql建一张表,每天用户登录都去表里新增一条记录
在redis里面可以这么解决呢?可以运用bitmap,每一个用户对应1个key,然后放置365位,每位代表1天,登录1天就在指定天对应位里置1,如下图
代码实现:
setbit sean 1 1 #用户sean在第2天里登录
setbit sean 7 1 #用户sean在第8天里登录
setbit sean 364 1 #用户sean在第365天里登录
STRLEN sean
BITCOUNT sean -2 -1 #选取用户sean 1年里最后16天的总登录天数
2、一知名线上商城618做活动:送礼物,大库需要备货多少礼物,假设有2E用户?
用户分为 僵尸用户/冷热用户/忠诚用户,因此不是有2E用户就送2E商品,需要统计出活跃用户的数量,例如统计1-2号上线用户总数,单个用户连续登录需要去重。
在redis里依旧可以使用bitmap,此时日期作为key,每个用户作为位,如图:
此时可以将两个key进行与运算,即可完成去重操作,然后使用bitcount统计位值为1的个数,即可统计出活跃用户个数
代码实现:
setbit 20190101 1 1 #1号用户01登录了
setbit 20190102 1 1 #2号用户01登录了
setbit 20190102 7 1 #2号用户08登录了
bitop or destkey 20190101 20190102 #01与02进行与运算
BITCOUNT destkey 0 -1 #得到所有的位值为1的个数,也就是总活跃用户数
正反向索引
redis中有许多的范围操作,因此就涉及到redis的索引
redis中,是存在正反向索引的,不但可以通过0,1,2进行访问指定偏移量数据,还可以用-1,-2表示从后向前访问。
拿string类型的getrange方法举例
set k1 hel
OK
GETRANGE k1 0 2
hel
GETRANGE k1 0 -1
hel
List
redis中,list的类型其实本质上是使用一个链表的结构进行存储,是一种存储多元素的结构,且它本身放入元素是有顺序性的,且元素是不支持去重的。
此时,首先可以观察一下此时的key,key上面此时会分别有两个属性,head和tail分别指向链表的头部和尾部。
而正如之前说的,list中的元素也有正反向索引之说。
想要查看list有哪些操作:
127.0.0.1:6379> help @list
BLPOP key [key ...] timeout
summary: Remove and get the first element in a list, or block until one is available
since: 2.0.0
BRPOP key [key ...] timeout
summary: Remove and get the last element in a list, or block until one is available
since: 2.0.0
BRPOPLPUSH source destination timeout
summary: Pop a value from a list, push it to another list and return it; or block until one is available
since: 2.2.0
LINDEX key index
summary: Get an element from a list by its index
since: 1.0.0
LINSERT key BEFORE|AFTER pivot value
summary: Insert an element before or after another element in a list
since: 2.2.0
LLEN key
summary: Get the length of a list
since: 1.0.0
LPOP key
summary: Remove and get the first element in a list
since: 1.0.0
LPUSH key value [value ...]
summary: Prepend one or multiple values to a list
since: 1.0.0
LPUSHX key value
summary: Prepend a value to a list, only if the list exists
since: 2.2.0
LRANGE key start stop
summary: Get a range of elements from a list
since: 1.0.0
LREM key count value
summary: Remove elements from a list
since: 1.0.0
LSET key index value
summary: Set the value of an element in a list by its index
since: 1.0.0
LTRIM key start stop
summary: Trim a list to the specified range
since: 1.0.0
RPOP key
summary: Remove and get the last element in a list
since: 1.0.0
RPOPLPUSH source destination
summary: Remove the last element in a list, prepend it to another list and return it
since: 1.2.0
RPUSH key value [value ...]
summary: Append one or multiple values to a list
since: 1.0.0
RPUSHX key value
summary: Append a value to a list, only if the list exists
since: 2.2.0
#LPUSH key value [value ...]
#summary: Prepend one or multiple values to a list
#since: 1.0.0
#向链表左侧依次向前插入元素(头插法)
127.0.0.1:6379> LPUSH list1 1 2 3
(integer) 3
127.0.0.1:6379> LRANGE list1 0 -1
1) "3"
2) "2"
3) "1"
#LPOP key
#summary: Remove and get the first element in a list
#since: 1.0.0
#删除并获得链表第一个元素(最左边)
127.0.0.1:6379> LPOP list1
"3"
127.0.0.1:6379> LPOP list1
"2"
127.0.0.1:6379> LPOP list1
"1"
#RPUSH key value [value ...]
#summary: Append one or multiple values to a list
#since: 1.0.0
#向链表右侧依次插入元素(尾插法)
127.0.0.1:6379> rpush list1 1 2 3
(integer) 3
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "2"
3) "3"
#RPOP key
#summary: Remove and get the last element in a list
#since: 1.0.0
#删除并获得链表第一个元素(最左边)
127.0.0.1:6379> RPOP list1
"3"
127.0.0.1:6379> RPOP list1
"2"
127.0.0.1:6379> RPOP list1
"1"
我们可以看到上面使用相同方向的添加和删除,效果看起来就是先进去的先出来了,是不是很像编程中的一种模型? 没错,就是栈,后入先出。
而反过来想,如果相反呢?
127.0.0.1:6379> rpush list1 1 2 3
(integer) 3
127.0.0.1:6379> lpop list1
"1"
127.0.0.1:6379> lpop list1
"2"
127.0.0.1:6379> lpop list1
"3"
看到效果了吗? 我们实现了另外一种模型, 队列, 先入先出。
因此可以做个总结:list的同向命令可以实现栈,反向命令可以实现队列。
上面我们有用到LRANGE,这里来说明一下:
#LRANGE key start stop
#summary: Get a range of elements from a list
#since: 1.0.0
#获取某个范围内的元素
LRANGE list1 0 -1
1) "1"
2) "2"
3) "3"
#LINDEX key index
#summary: Get an element from a list by its index
#since: 1.0.0
#从给定索引获取元素
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "666"
3) "3"
127.0.0.1:6379> LINDEX list1 1
"666"
#LREM key count value
#summary: Remove elements from a list
#since: 1.0.0
#移除count个值为value的元素 这个count可以为正数可以为负数, 正数时从前向后删除|count|个该value元素,负数时从后向前删除|count|个该value元素
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "666"
3) "3"
4) "3"
5) "3"
6) "3"
7) "6"
8) "7"
9) "3"
10) "3"
#count为正数
127.0.0.1:6379> LREM list1 2 3
(integer) 2
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "666"
3) "3"
4) "3"
5) "6"
6) "7"
7) "3"
8) "3"
#count为负数
127.0.0.1:6379> LREM list1 -2 3
(integer) 2
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "666"
3) "3"
4) "3"
5) "6"
6) "7"
#LSET key index value
#summary: Set the value of an element in a list by its index
#since: 1.0.0
#设置某个索引的元素
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> LSET list1 1 666
OK
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "666"
3) "3"
#LINSERT key BEFORE|AFTER pivot value
#summary: Insert an element before or after another element in a list
#since: 2.2.0
#从前向后找到某个元素为pivot的,并在它的前面或者后面插入该value值
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "666"
3) "3"
4) "3"
5) "6"
6) "7"
#在666前面插入123
127.0.0.1:6379> LINSERT list1 before 666 123
(integer) 7
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "123"
3) "666"
4) "3"
5) "3"
6) "6"
7) "7"
#在666后面插入123
127.0.0.1:6379> LINSERT list1 after 666 123
(integer) 8
127.0.0.1:6379> LRANGE list1 0 -1
1) "1"
2) "123"
3) "666"
4) "123"
5) "3"
6) "3"
7) "6"
8) "7"
#LLEN key
#summary: Get the length of a list
#since: 1.0.0
#获取此list的长度
127.0.0.1:6379> LLEN list1
(integer) 8
#LTRIM key start stop
#summary: Trim a list to the specified range
#since: 1.0.0
#对选定范围两侧的元素进行清空
127.0.0.1:6379> LRANGE list2 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "444"
127.0.0.1:6379> LTRIM list2 2 -2
OK
127.0.0.1:6379> LRANGE list2 0 -1
1) "3"
2) "2"
3) "1"
单播队列
redis还可以完成单播队列的功能,通过它的BLPOP 或者BRPOP完成
#BLPOP key [key ...] timeout
#summary: Remove and get the first element in a list, or block until one is available
#since: 2.0.0
#阻塞等待直到一个list中的第一个元素可用时对其进行删除并获取
#BRPOP key [key ...] timeout
#summary: Remove and get the last element in a list, or block until one is available
#since: 2.0.0
#阻塞等待直到一个list中的最后一个元素可用时对其进行删除并获取
来实现这个功能:
客户端1:
127.0.0.1:6379> BLPOP list2 0
此时会一直阻塞等待。。。。
客户端2:
127.0.0.1:6379> RPUSH list2 333 444
(integer) 2
向list中推入元素
此时客户端1:
127.0.0.1:6379> BLPOP list2 0
1) "list2"
2) "333"
(57.78s)
发现,得到了客户端1推送的第一个元素
至此,我们发现一个List,其实是可以有这么多用途的:
Hash
如果学过java,那么一定知道java中有一个类型叫hashmap,这里通俗来说,可以把hash就当成一个hashmap。
按照之前的惯例,我们来看下hash有哪些操作:
127.0.0.1:6379> help @hash
HDEL key field [field ...]
summary: Delete one or more hash fields
since: 2.0.0
HEXISTS key field
summary: Determine if a hash field exists
since: 2.0.0
HGET key field
summary: Get the value of a hash field
since: 2.0.0
HGETALL key
summary: Get all the fields and values in a hash
since: 2.0.0
HINCRBY key field increment
summary: Increment the integer value of a hash field by the given number
since: 2.0.0
HINCRBYFLOAT key field increment
summary: Increment the float value of a hash field by the given amount
since: 2.6.0
HKEYS key
summary: Get all the fields in a hash
since: 2.0.0
HLEN key
summary: Get the number of fields in a hash
since: 2.0.0
HMGET key field [field ...]
summary: Get the values of all the given hash fields
since: 2.0.0
HMSET key field value [field value ...]
summary: Set multiple hash fields to multiple values
since: 2.0.0
HSCAN key cursor [MATCH pattern] [COUNT count]
summary: Incrementally iterate hash fields and associated values
since: 2.8.0
HSET key field value
summary: Set the string value of a hash field
since: 2.0.0
HSETNX key field value
summary: Set the value of a hash field, only if the field does not exist
since: 2.0.0
HSTRLEN key field
summary: Get the length of the value of a hash field
since: 3.2.0
HVALS key
summary: Get all the values in a hash
since: 2.0.0
可以发现和hashmap的操作相差不多,这里我嫌麻烦,就不一一再讲应用了。
应用场景
点赞,收藏,详情页
Set
set与list比较相似,但区别是,set是无序的,且会对内部存储的元素进行去重。
来看看有哪些操作:
help @set
SADD key member [member ...]
summary: Add one or more members to a set
since: 1.0.0
SCARD key
summary: Get the number of members in a set
since: 1.0.0
SDIFF key [key ...]
summary: Subtract multiple sets
since: 1.0.0
SDIFFSTORE destination key [key ...]
summary: Subtract multiple sets and store the resulting set in a key
since: 1.0.0
SINTER key [key ...]
summary: Intersect multiple sets
since: 1.0.0
SINTERSTORE destination key [key ...]
summary: Intersect multiple sets and store the resulting set in a key
since: 1.0.0
SISMEMBER key member
summary: Determine if a given value is a member of a set
since: 1.0.0
SMEMBERS key
summary: Get all the members in a set
since: 1.0.0
SMOVE source destination member
summary: Move a member from one set to another
since: 1.0.0
SPOP key [count]
summary: Remove and return one or multiple random members from a set
since: 1.0.0
SRANDMEMBER key [count]
summary: Get one or multiple random members from a set
since: 1.0.0
SREM key member [member ...]
summary: Remove one or more members from a set
since: 1.0.0
SSCAN key cursor [MATCH pattern] [COUNT count]
summary: Incrementally iterate Set elements
since: 2.8.0
SUNION key [key ...]
summary: Add multiple sets
since: 1.0.0
SUNIONSTORE destination key [key ...]
summary: Add multiple sets and store the resulting set in a key
since: 1.0.0
从这些操作,我们大致可以总结出set的特点:
随机事件的应用场景
针对随机事件,可以来聊一聊。
可以使用set类型中的各种随机操作来完成日常中的一些需求
先介绍一个操作:
#SRANDMEMBER key [count]
#summary: Get one or multiple random members from a set
#since: 1.0.0
#随机获取1个元素或多个元素
#这里的count根据取值不同,选取元素策略也有所不同:
#如果count>0 会返回一个去重的结果集(但总数不超过现有总数)
#如果count=0 不返回任何内容
#如果count<0 会返回一个可能重复的结果集,但个数一定是期望的个数
这里我们可以分析一下如何合理利用在哪些场景:
1、假设一公司发放奖品,奖品个数大于人数,公司希望给每个人都可以多得到几件礼物。
这种count就可以取负数,将set里放入人名,取出的结果就很可能会一个人出现多次,符合需求。
例如一共有4个人:
127.0.0.1:6379> SMEMBERS peoples
1) "wangwu"
2) "lisi"
3) "zhanggsan"
4) "liming"
然后给这4个人分发20件礼物,可以这样做:
127.0.0.1:6379> SRANDMEMBER peoples -20
1) "liming"
2) "lisi"
3) "liming"
4) "zhanggsan"
5) "lisi"
6) "liming"
7) "lisi"
8) "wangwu"
9) "lisi"
10) "zhanggsan"
11) "wangwu"
12) "zhanggsan"
13) "zhanggsan"
14) "liming"
15) "liming"
16) "lisi"
17) "liming"
18) "zhanggsan"
19) "wangwu"
20) "wangwu"
2、假设公司年会,一定是礼物数远小于人数的,此时count可以使用正数
假设还是之前那四个人,但礼物只有2个
127.0.0.1:6379> SRANDMEMBER peoples 2
1) "lisi"
2) "wangwu"
127.0.0.1:6379> SRANDMEMBER peoples 2
1) "lisi"
2) "liming"
3、实际上,我们在年会上,都是1人分发1个号码,一轮一轮抽奖,当中奖后,将从待选区被移除,此时这个方法可能就不太适用了,可以用另外一个指令:
SPOP key [count]
summary: Remove and return one or multiple random members from a set
since: 1.0.0
#随机移除并返回count个数的元素
127.0.0.1:6379> SPOP peoples
"liming"
127.0.0.1:6379> SPOP peoples
"zhanggsan"
127.0.0.1:6379> SPOP peoples
"wangwu"
127.0.0.1:6379> SPOP peoples
"lisi"
127.0.0.1:6379> SPOP peoples
(nil)
Zset(sorted-set)
接下来, 就是我们的最后一种类型,zset,和set比较相似,它也是会对集合内元素进行去重操作(更准确些,应该叫更新),但不同的是它是又是一种支持对集合内元素进行排序的数据结构
既然要排序,自然需要一个东西来标识一个元素是多大,因此在zset中有一个score的存在。
zset有一个特点是存储元素在物理内存中的存放是从左到右,从小到大的。且不会随命令的操作而改变元素的位置。
还是先来看下它有哪些命令:
127.0.0.1:6379> help @sorted_set
BZPOPMAX key [key ...] timeout
summary: Remove and return the member with the highest score from one or more sorted sets, or block until one is available
since: 5.0.0
BZPOPMIN key [key ...] timeout
summary: Remove and return the member with the lowest score from one or more sorted sets, or block until one is available
since: 5.0.0
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
summary: Add one or more members to a sorted set, or update its score if it already exists
since: 1.2.0
ZCARD key
summary: Get the number of members in a sorted set
since: 1.2.0
ZCOUNT key min max
summary: Count the members in a sorted set with scores within the given values
since: 2.0.0
ZINCRBY key increment member
summary: Increment the score of a member in a sorted set
since: 1.2.0
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
summary: Intersect multiple sorted sets and store the resulting sorted set in a new key
since: 2.0.0
ZLEXCOUNT key min max
summary: Count the number of members in a sorted set between a given lexicographical range
since: 2.8.9
ZPOPMAX key [count]
summary: Remove and return members with the highest scores in a sorted set
since: 5.0.0
ZPOPMIN key [count]
summary: Remove and return members with the lowest scores in a sorted set
since: 5.0.0
ZRANGE key start stop [WITHSCORES]
summary: Return a range of members in a sorted set, by index
since: 1.2.0
ZRANGEBYLEX key min max [LIMIT offset count]
summary: Return a range of members in a sorted set, by lexicographical range
since: 2.8.9
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
summary: Return a range of members in a sorted set, by score
since: 1.0.5
ZRANK key member
summary: Determine the index of a member in a sorted set
since: 2.0.0
ZREM key member [member ...]
summary: Remove one or more members from a sorted set
since: 1.2.0
ZREMRANGEBYLEX key min max
summary: Remove all members in a sorted set between the given lexicographical range
since: 2.8.9
ZREMRANGEBYRANK key start stop
summary: Remove all members in a sorted set within the given indexes
since: 2.0.0
ZREMRANGEBYSCORE key min max
summary: Remove all members in a sorted set within the given scores
since: 1.2.0
ZREVRANGE key start stop [WITHSCORES]
summary: Return a range of members in a sorted set, by index, with scores ordered from high to low
since: 1.2.0
ZREVRANGEBYLEX key max min [LIMIT offset count]
summary: Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.
since: 2.8.9
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
summary: Return a range of members in a sorted set, by score, with scores ordered from high to low
since: 2.2.0
ZREVRANK key member
summary: Determine the index of a member in a sorted set, with scores ordered from high to low
since: 2.0.0
ZSCAN key cursor [MATCH pattern] [COUNT count]
summary: Incrementally iterate sorted sets elements and associated scores
since: 2.8.0
ZSCORE key member
summary: Get the score associated with the given member in a sorted set
since: 1.2.0
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
summary: Add multiple sorted sets and store the resulting sorted set in a new key
since: 2.0.0
挑选一些常用的命令进行讲解:
#ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
#summary: Add one or more members to a sorted set, or update its score if it already exists
#since: 1.2.0
#添加元素 每个元素都要带有分值
ZADD z1 8 apple 10 orange 12 banana
#ZRANGE key start stop [WITHSCORES]
#summary: Return a range of members in a sorted set, by index
#since: 1.2.0
#按照索引范围获取由低到高排序的元素
127.0.0.1:6379> ZRANGE z1 0 -1
1) "apple"
2) "orange"
3) "banana"
127.0.0.1:6379> ZRANGE z1 0 -1 withscores
1) "apple"
2) "8"
3) "orange"
4) "10"
5) "banana"
6) "12"
#ZREVRANGE key start stop [WITHSCORES]
#summary: Return a range of members in a sorted set, by index, with scores ordered from high to low
#since: 1.2.0
#按照索引范围获取由高到低排序的元素
127.0.0.1:6379> ZREVRANGE z1 0 -1
1) "banana"
2) "orange"
3) "apple"
#ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
#summary: Return a range of members in a sorted set, by score
#since: 1.0.5
#按照分值范围获取元素
127.0.0.1:6379> ZRANGEBYSCORE z1 10 12
1) "orange"
2) "banana"
#ZSCORE key member
#summary: Get the score associated with the given member in a sorted set
#since: 1.2.0
#获取元素的分数
127.0.0.1:6379> ZSCORE z1 apple
"8"
#ZRANK key member
#summary: Determine the index of a member in a sorted set
#since: 2.0.0
#获取指定元素的排名
127.0.0.1:6379> ZRANK z1 apple
(integer) 0
127.0.0.1:6379> ZRANK z1 orange
(integer) 1
127.0.0.1:6379> ZRANK z1 banana
(integer) 2
集合操作
zset也支持多集合的操作,但因为zset一个元素除了值本身外,还有score,那两个集合进行合并的时候留谁舍谁呢?
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
summary: Add multiple sorted sets and store the resulting sorted set in a new key
since: 2.0.0
#对任意个数的zset进行合并操作 numkeys指定参与的zset个数
#weights可以分别定义每个zset在参与的时候其每个元素的分值大小缩放比例 aggregate定义在遇到重复元素值时要做的操作, 不填默认为SUM操作
127.0.0.1:6379> ZADD z1 20 zhanggsan 30 lisi 60 wangwu
(integer) 3
127.0.0.1:6379> ZADD z2 60 zhangsan 66 liming
(integer) 2
127.0.0.1:6379> ZRANGE z1 0 -1 withscores
1) "zhangsan"
2) "20"
3) "lisi"
4) "30"
5) "wangwu"
6) "60"
127.0.0.1:6379> ZRANGE z2 0 -1 withscores
1) "zhangsan"
2) "60"
3) "liming"
4) "66"
#接下来对两个集合进行操作
#不指定aggregate 默认对重复元素进行 SUM操作
127.0.0.1:6379> ZRANGE unkey1 0 -1 withscores
1) "lisi"
2) "30"
3) "wangwu"
4) "60"
5) "liming"
6) "66"
7) "zhangsan"
8) "80"
#指定各zset参与操作的score分值缩放比例
127.0.0.1:6379> ZUNIONSTORE unkey2 2 z1 z2 WEIGHTS 1 0.5
(integer) 4
127.0.0.1:6379> ZRANGE unkey2 0 -1 withscores
1) "lisi"
2) "30"
3) "liming"
4) "33"
5) "zhangsan"
6) "50"
7) "wangwu"
8) "60"
#指定aggregate 对重复元素进行 MAX操作 也就是留下最大的那个
127.0.0.1:6379> ZUNIONSTORE unkey4 2 z1 z2 AGGREGATE MAX
(integer) 4
127.0.0.1:6379> ZRANGE unkey4 0 -1 withscores
1) "lisi"
2) "30"
3) "wangwu"
4) "60"
5) "zhangsan"
6) "60"
7) "liming"
当然,如果仅仅只有这些,这个类型是很少会被人使用的。
zset类型是支持进行计算的
#ZINCRBY key increment member
#summary: Increment the score of a member in a sorted set
#since: 1.2.0
#将元素的分数进行增加
127.0.0.1:6379> ZRANGE z1 0 -1 withscores
1) "apple"
2) "8"
3) "orange"
4) "10"
5) "banana"
6) "12"
127.0.0.1:6379> ZINCRBY z1 20 apple
"28"
127.0.0.1:6379> ZRANGE z1 0 -1 withscores
1) "orange"
2) "10"
3) "banana"
4) "12"
5) "apple"
6) "28"
从上可以看出,,zset会动态实时维护它们的排名,随着计算而变动。
应用场景
试想一下在线网游的游戏排行榜,杀怪越多的人排行越高,这个数值频繁会发生变动,redis作为一个内存型数据库比较合适,而此时使用zset天然支持的"排名系统"也是个不错的选择。
存储原理
由上可以看出,zset要实时维护一个集合里元素的顺序,那它是如何保证效率高效的呢?
我们首先想到的,为了保证顺序,它内部有可能会是使用一个链表结构来进行元素的存储:
但随着数据量增多,链表的时间复杂度O(n)会使得检索等操作变得越来越慢。
那redis怎么做的呢?
redis使用了一种数据结构:skip list(跳表)
这是一个什么结构呢?
其实简单来说,它就是在链表的基础上,多了几“层”
如图,在一层的链表基础上,每隔一些元素,就会有1个元素在上层中也有它的存在。
这样有什么好处呢?
一次插入
我们试想一下, 我们使用这个结构新增一个元素的过程:
例如我们要插入8。
此时会从最上层开始从左向右遍历,发现8是3和11中间的值,因此此时可以向下降层。
在第二层发现8是3-11之间的,继续降层,到达第一层
此时由11开始向左找,发现8是7-11之间的。
此时只需要在7和11之间插入8 ,然后将指针的引用切换一下,就可完成了插入。
一个元素插入完成后,会随机向上层造一个自身的数,具体造几层是随机的。
造层的细节
接着上面说的,当8完成插入后,会向左一直找,直到找到3,发现3有一个上层的指向,
顺着指向继续移动,到上层的3,此时发现层次就是2层了。
开始继续向右移动,发现7是在3-11之间的, 因此只需要将3指向7,7再指向11, 只需要改变一下指针的引用,就完成了一个元素在一层的生成。。
一次删除
从上向下,找到范围,确定元素,移除元素,将元素左右边界的元素进行指针关联修复引用就可完成了。
一次更新
一次更新其实可以理解成先把元素删除掉,修复指针引用后,然后走一遍插入的操作。
一次查询
无论增删改,都是需要先进行查询的,查找从上向下。
有没有发现这样的结构有点像树? 这样使得遍历比较少的节点就可以完成插入。
其实跳表还可以叫平衡树,它对于增删改查综合的能力算是相对最优的。
至此,redis的五种数据类型就介绍完了。
本人只对其中比较有特点的进行了讲解,如果想了解更全面的用法可以参考redis官方网站:
http://www.redis.cn/