主要是命令相关

第一章 初识Redis

1.redis是基于键值对的NoSQL.

2.redis的值可以是 string, hash, list, set, zset, bitmaps, hyperloglog, geo

3.redis的值不仅可以是字符串还可以是具体的数据结构

4.redis的2种持久方案:rdb和aof.

5.redis-server XXX.conf可以以conf的配置启动redis.

6.redis-cli shutdown可以关闭redis. 不要使用kill -9 杀死redis进程,可能会造成AOF和复制丢失数据的问题.

第二章 API的理解和使用

2.1预备

1.keys * 可以列出所有键, dbsize返回所有键的总数.dbsize时间复杂度是o(1),keys是o(n).所以键太多的时候不要使用keys *

另外实验发现keys 后面*代表任意数量的字符 ?代表单个字符

2.exists查看键是否存在,del删除键,del后面可以跟任意数量的键,比如del a b c .....

3. expire可以设置键过期时间(秒),剩余时间可以使用ttl查看.

127.0.0.1:6379> expire abcd  -99 //设置负数,直接过期
(integer) 1
127.0.0.1:6379> ttl abcd
(integer) -2 // ttl 大于0表示剩余秒, -1表示键没设置过期时间, -2表示键不存在

4.type key可以查看key的数据结构

127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> LPUSH b 1 2 3 4 5
(integer) 5
127.0.0.1:6379> type a
string
127.0.0.1:6379> type b
list 127.0.0.1:6379> type rrr //不存在的key
none

5.type命令返回的是redis对外的数据结构.每种数据结构对内还有N种内部编码实现.1种内部实现也可以对应N个外部数据结构.

使用object encoding查看内部数据编码

127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> set b 2
OK
127.0.0.1:6379> lpush c 1 2 3 4
(integer) 4
127.0.0.1:6379> OBJECT encoding a
"int"
127.0.0.1:6379> OBJECT encoding b
"int"
127.0.0.1:6379> OBJECT encoding c
"ziplist"
127.0.0.1:6379> set d qqq
OK
127.0.0.1:6379> OBJECT encoding d
"embstr"
127.0.0.1:6379> set e 99999999999999
OK
127.0.0.1:6379> OBJECT encoding e
"int"
127.0.0.1:6379> set f 9999999999999999999999999.9999999999999999999999
OK
127.0.0.1:6379> OBJECT encoding f
"raw"
127.0.0.1:6379> set g 123.456
OK
127.0.0.1:6379> OBJECT encoding g
"embstr"
127.0.0.1:6379> set h 99999999999999999999999999999999999999999999999
OK
127.0.0.1:6379> OBJECT encoding h
"raw"

我觉得对于我们外部其他语言使用redis来说可能不太关心内部实现而是关心接口返回的外部数据结构..这个有点像java里通过接口引用具体的集合对象..

6.每次客户端调用都经历了发送命令,执行命令,返回结果三个过程.每条命令从客户端到达服务端以后不会被立刻执行,所有命令都回进入1个队列中,然后逐个被执行.

2.2字符串

1.字符串值不能超过512M

2.实验

127.0.0.1:> set k1 abc //set设置值
OK
127.0.0.1:> set k2 def ex 999 //ex设置过期秒数,px设置毫秒数
OK
127.0.0.1:> ttl k2
(integer)
127.0.0.1:> set k1 change xx // xx key 存在才更新不然不操作,用于更新
OK
127.0.0.1:> get k1
"change"
127.0.0.1:> set k1 qqq
OK
127.0.0.1:> get k1
"qqq"
127.0.0.1:> ttl k2
(integer)
127.0.0.1:> set k3 ttt nx // nx key 不存在才操作,用于插入
OK
127.0.0.1:> get k3
"ttt"
127.0.0.1:> set k3 www xx
OK
127.0.0.1:> get k3
"www"
127.0.0.1:> set k3 ppp nx // 不存在key,用nx操作.
(nil)
127.0.0.1:> get k3
"www"

3.setex和setnx的实验

setex key seconds value

setnx key value

setex多了1个seconds不知道为啥

127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> setnx k1 change //setnx不像set nx返回nil而是返回了操作了0个key
(integer) 0
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> exists k2
(integer) 0
127.0.0.1:6379> setnx k2 v2 // 操作成功返回操作了1个key的数量
(integer) 1
127.0.0.1:6379> setnx k2 v22
(integer) 0
127.0.0.1:6379>

127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> setex k1 999 v999
OK
127.0.0.1:6379> ttl k1
(integer) 996
127.0.0.1:6379>

setnx可以作为分布式锁的一种方案.因为redis是单线程只有1个操作会成功返回1,其他都是0

4.mset和mget批量操作

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v4
OK
127.0.0.1:6379> mget k1 k2 k3 k4
1) "v1"
2) "v2"
3) "v4"
4) (nil)
127.0.0.1:6379>

5.计数

incr incrby自增,decr decrby自减

127.0.0.1:6379> set k1 NaN
OK
127.0.0.1:6379> INCR k1 //不是数字自增报错
(error) ERR value is not an integer or out of range
127.0.0.1:6379> set k2 1
OK
127.0.0.1:6379> incr k2
(integer) 2
127.0.0.1:6379> incr k2
(integer) 3
127.0.0.1:6379> get k2
"3"
127.0.0.1:6379> incrby k2 3
(integer) 6
127.0.0.1:6379> incrby k2 NaN //同incr
(error) ERR value is not an integer or out of range
127.0.0.1:6379> incrby k2 -3 // 自增指定数量可以自增负数
(integer) 3
127.0.0.1:6379> decr k1
(error) ERR value is not an integer or out of range
127.0.0.1:6379> decr k2 1
(error) ERR wrong number of arguments for 'decr' command
127.0.0.1:6379> decr k2
(integer) 2
127.0.0.1:6379> decrby k2 2
(integer) 0
127.0.0.1:6379> decrby k2 -9 //同自增
(integer) 9
127.0.0.1:6379> exists k3
(integer) 1
127.0.0.1:6379> del k3
(integer) 1
127.0.0.1:6379> exists k3
(integer) 0
127.0.0.1:6379> incr k3 //操作不存在的key,值直接当成0
(integer) 1
127.0.0.1:6379> del k3
(integer) 1
127.0.0.1:6379> incr k3 3
(error) ERR wrong number of arguments for 'incr' command
127.0.0.1:6379> incrby k3 3 //同incr
(integer) 3
127.0.0.1:6379>
127.0.0.1:6379> del k1
(integer) 1
127.0.0.1:6379> del k1
(integer) 0
127.0.0.1:6379> set k1 0.1
OK
127.0.0.1:6379> incr k1 //自增自减只能用于整数
(error) ERR value is not an integer or out of range
127.0.0.1:6379>

6.append追加字符串

127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> del k1
(integer) 1
127.0.0.1:6379> set k1 hello
OK
127.0.0.1:6379> APPEND k1 " world" //返回字符串长度
(integer) 11
127.0.0.1:6379> get k1
"hello world"
127.0.0.1:6379>
127.0.0.1:6379> get k1
"hello world"
127.0.0.1:6379> APPEND k1 "'''"
(integer) 14
127.0.0.1:6379> APPEND k1 """"
Invalid argument(s)
127.0.0.1:6379> APPEND k1 "\"\"" //追加"可以用/"
(integer) 16
127.0.0.1:6379> get k1
"hello world'''\"\""
127.0.0.1:6379> set k1 ""
OK
127.0.0.1:6379> get k1
""
127.0.0.1:6379> append k1 ""
(integer) 0
127.0.0.1:6379> append k1 "
Invalid argument(s)
127.0.0.1:6379> append k1 ''
(integer) 0
127.0.0.1:6379> append k1 '"' //或者用'"'
(integer) 1
127.0.0.1:6379> get k1
"\""
127.0.0.1:6379> append k1 "'"
(integer) 2
127.0.0.1:6379> get k1
"\"'"
127.0.0.1:6379>

7.用strlen返回字符串长度,用getset可以设置新值并且返回原本字符串的值(有可能是nil).setrange key offset value可以改变指定位置字符,从0开始计数返回字符串长度

getrange key start end返回substr. 0开始计数,start和end都包括

127.0.0.1:6379> set k1 helloworld
OK
127.0.0.1:6379> GETRANGE k1 1 2
"el"
127.0.0.1:6379>

127.0.0.1:6379> GETRANGE k1 2 -1 // -1是最后1个字符串
"lloworld"
127.0.0.1:6379> GETRANGE k1 2 -2
"lloworl"
127.0.0.1:6379> GETRANGE k1 2 0
""
127.0.0.1:6379> GETRANGE k1 2 -0
""
127.0.0.1:6379>

8.字符串内部有3种编码,int 8字节长整型,embstr<=39字节的字符串,raw>39字节的字符串

127.0.0.1:6379> set k1 9203372036054477800
OK
127.0.0.1:6379> OBJECT encoding k1
"int"
127.0.0.1:6379> set k1 9233372000000000000
OK
127.0.0.1:6379> OBJECT encoding k1
"embstr"

8字节是64位,java里long的范围应该是

-9233372036854477808-9233372036854477808 (https://zhidao.baidu.com/question/256678932.html)

但是不知道为什么这里redis似乎不是

127.0.0.1:6379> set k1 呵 //length=3
OK
127.0.0.1:6379> object encoind k1
(error) ERR Syntax error. Try OBJECT (refcount|encoding|idletime)
127.0.0.1:6379> object encoding k1
"embstr"
127.0.0.1:6379> strlen k1
(integer) 3
127.0.0.1:6379> set k1 呵呵呵呵呵呵呵呵呵呵呵呵呵 //length=39
OK
127.0.0.1:6379> object encoding k1
"embstr"
127.0.0.1:6379> set k1 呵呵呵呵呵呵呵呵呵呵呵呵呵a //40
OK
127.0.0.1:6379> strlenth k1
(error) ERR unknown command 'strlenth'
127.0.0.1:6379> strlen k1
(integer) 40
127.0.0.1:6379> object encoding k1
"raw"
127.0.0.1:6379>

似乎是1个中文UTF-8占3个字节的缘故

2.3哈希

1.

hset key field value

het key field

127.0.0.1:6379> hset k1 f1 v1
(integer) 1
127.0.0.1:6379> hget k1
(error) ERR wrong number of arguments for 'hget' command
127.0.0.1:6379> hget k1 f1
"v1"
127.0.0.1:6379> HGETALL k1
1) "f1"
2) "v1"
127.0.0.1:6379>

2.hdel key field [...field]

127.0.0.1:6379> hset k1 f1 v1
(integer) 1
127.0.0.1:6379> hset k1 f2 v2
(integer) 1
127.0.0.1:6379> hset k1 f3 v3
(integer) 1
127.0.0.1:6379> hdel k1 f1 f2 //返回删除个数
(integer) 2
127.0.0.1:6379> hget k1
(error) ERR wrong number of arguments for 'hget' command
127.0.0.1:6379> hgetall k1
1) "f3"
2) "v3"
127.0.0.1:6379>

3.hlen key返回field的个数

4.hmget field [field....]

hmset key field value [field value...]

批量操作hash

127.0.0.1:6379> hmset k1 f1 v1 f2 v2 f3 v3
OK
127.0.0.1:6379> mhget k1 f1 f2 f3
(error) ERR unknown command 'mhget'
127.0.0.1:6379> hmget k1 f1 f2 f3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> HGETALL k1
1) "f1"
2) "v1"
3) "f2"
4) "v2"
5) "f3"
6) "v3"
127.0.0.1:6379>

5.

hexists key field 判断field是否存在

127.0.0.1:6379> HEXISTS l1 f1
(integer) 0
127.0.0.1:6379> HEXISTS k1 f1
(integer) 1
127.0.0.1:6379> hget k1 f1
"v1"
127.0.0.1:6379> hget l1 f1
(nil)
127.0.0.1:6379>

6.

hkeys * 获取所有field

hvals获取所有value

hgetall key 获取所有fieldvalue

127.0.0.1:6379> HKEYS k1
1) "f1"
2) "f2"
3) "f3"
127.0.0.1:6379> HVALS k1
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> HGETALL k1
1) "f1"
2) "v1"
3) "f2"
4) "v2"
5) "f3"
6) "v3"
127.0.0.1:6379>

7.

没有hincr命令.hincrby和hincrbyfloat和hstrlen与String的类似

8.

hash的内部编码有ziplist(个数小于512,或者所有值小于64字节),hashtable

2.4列表

一个列表最多可以存储2^32 -1 个元素.

lpush key value [value...]

rpush key value[value...]

127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> del k1
(integer) 1
127.0.0.1:6379> lpush a b c
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> lpush k1 a b c
(integer) 3
127.0.0.1:6379> rpush k1 d e f
(integer) 6
127.0.0.1:6379> lrange k1 0 -1
1) "c"
2) "b"
3) "a"
4) "d"
5) "e"
6) "f"
127.0.0.1:6379> lrange k1 2 3 //取下标对应的元素,从0开始
1) "a"
2) "d"
127.0.0.1:6379>

linsert key before|after pivotValue value 在pivotValue之前或者之后插入元素

127.0.0.1:6379> lrange k1 0 -1
1) "c"
2) "b"
3) "a"
4) "d"
5) "e"
6) "f"
127.0.0.1:6379>
127.0.0.1:6379> LINSERT k1 before a 9
(integer) 7
127.0.0.1:6379> lrange k1 0 -1
1) "c"
2) "b"
3) "9"
4) "a"
5) "d"
6) "e"
7) "f"
127.0.0.1:6379> LINSERT k1 after a 8
(integer) 8
127.0.0.1:6379> lrange k1 0 -1
1) "c"
2) "b"
3) "9"
4) "a"
5) "8"
6) "d"
7) "e"
8) "f"
127.0.0.1:6379> lpush k1 a
(integer) 9
127.0.0.1:6379> lrange k1 0 -1
1) "a"
2) "c"
3) "b"
4) "9"
5) "a"
6) "8"
7) "d"
8) "e"
9) "f"
127.0.0.1:6379> LINSERT k1 after a 7 //在找到的第一个元素后面添加然后直接return
(integer) 10
127.0.0.1:6379> lrange k1 0 -1
1) "a"
2) "7"
3) "c"
4) "b"
5) "9"
6) "a"
7) "8"
8) "d"
9) "e"
10) "f"
127.0.0.1:6379> rINSERT k1 after a 7 //没有rinsert
(error) ERR unknown command 'rINSERT'
127.0.0.1:6379>

lindex key index 获取指定位置的元素,负数就是从最后面1个元素开始数

127.0.0.1:6379> lrange k1 0 -1
1) "a"
2) "7"
3) "c"
4) "b"
5) "9"
6) "a"
7) "8"
8) "d"
9) "e"
10) "f"
127.0.0.1:6379> lindex k1 1
"7"
127.0.0.1:6379> lindex k1 -2 //倒数第二个元素
"e"
127.0.0.1:6379>

llen key获取列表元素个数

lpop key和rpop key用于删除元素

lrem key count value找到value以后最多删除count个值为value的元素

count>0才能够左往右删除,<0从右往左,=0全部删除

127.0.0.1:6379> lrange k1 0 -1
1) "a"
2) "7"
3) "c"
4) "b"
5) "9"
6) "a"
7) "8"
8) "d"
9) "e"
10) "f"
127.0.0.1:6379> lrem k1 2 a //2个a都删除了
(integer) 2
127.0.0.1:6379> lrange k1 0 -1
1) "7"
2) "c"
3) "b"
4) "9"
5) "8"
6) "d"
7) "e"
8) "f"
127.0.0.1:6379> lrem k1 8 -1
(integer) 0
127.0.0.1:6379> lrem k1 -1 8 //删除1个8右边开始
(integer) 1
127.0.0.1:6379> lrange k1 0 -1
1) "7"
2) "c"
3) "b"
4) "9"
5) "d"
6) "e"
7) "f"
127.0.0.1:6379> lrem k1 0 e //所有e都删除
(integer) 1
127.0.0.1:6379> lrange k1 0 -1
1) "7"
2) "c"
3) "b"
4) "9"
5) "d"
6) "f"
127.0.0.1:6379>

ltrim key start end 按照索引保留元素

127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> lrange k1 0 -1
1) "7"
2) "c"
3) "b"
4) "9"
5) "d"
6) "f"
127.0.0.1:6379> LTRIM k1 1 3
OK
127.0.0.1:6379> lrange k1 0 -1
1) "c"
2) "b"
3) "9"
127.0.0.1:6379>

lset key index newValue可以修改index的元素

127.0.0.1:6379> lrange k1 0 -1
1) "c"
2) "b"
3) "9"
127.0.0.1:6379> lset k1 0 a
OK
127.0.0.1:6379> lrange k1 0 -1
1) "a"
2) "b"
3) "9"
127.0.0.1:6379> lset k1 99 a
(error) ERR index out of range
127.0.0.1:6379>

blpop key [key...] timeout 弹出key最左边的元素,阻塞timeout秒.

brpop同理

127.0.0.1:6379> lrange k1 0 -1
1) "a"
2) "b"
3) "9"
127.0.0.1:6379> blpop k1 9
1) "k1"
2) "a"
127.0.0.1:6379> exists k2
(integer) 1
127.0.0.1:6379> del k2
(integer) 1
127.0.0.1:6379> del k2
(integer) 0
127.0.0.1:6379> blpop k2 9
(nil)
(9.02s)
127.0.0.1:6379>

多个key只要有1个能返回就立即返回.

多个客户端同时阻塞,添加元素后.哪个客户端命令先执行哪个就先返回,剩下的继续阻塞.

列表的内部实现有ziplist和linkedlist.条件范围同hash

使用场景:

lpush和brpop可以实现消息队列.

2.5集合

集合不允许重复yuansu,zuiduo储存2^32-1个元素.

sadd key element [element...] 新增元素

srem key element [element...] 删除元素

scard key 计算元素个数(竟然不是slen...)

smenbers key 返回集合所有元素

127.0.0.1:6379> exists k3
(integer) 1
127.0.0.1:6379> type k3
string
127.0.0.1:6379> get k3
"3vv\n"
127.0.0.1:6379> del k3
(integer) 1
127.0.0.1:6379> sadd k3 e1 e2 e3 e4
(integer) 4
127.0.0.1:6379> srem e2 e5
(integer) 0
127.0.0.1:6379> srem k3 e2 e5 //e2存在 e5不存在
(integer) 1 //成功删除e2返回结果1
127.0.0.1:6379> scard k3 //返回集合元素个数为3
(integer) 3
127.0.0.1:6379> SMEMBERS k3 //查看所有元素
1) "e1"
2) "e4"
3) "e3"
127.0.0.1:6379>

sismenmber key element 判断元素是否在集合内

srandmember key [count] 随机返回count个元素,默认为1

spop 随机弹出1个元素

127.0.0.1:6379> smembers k3
1) "e1"
2) "e4"
3) "e3"
127.0.0.1:6379> sismember k3 e1 //存在元素返回1
(integer) 1
127.0.0.1:6379> sismember k3 e2 //不存在返回0
(integer) 0
127.0.0.1:6379> sismember k3 e1 e2
(error) ERR wrong number of arguments for 'sismember' command
127.0.0.1:6379> sranmember key 1
(error) ERR unknown command 'sranmember'
127.0.0.1:6379> sranmember k3 1
(error) ERR unknown command 'sranmember'
127.0.0.1:6379> srandmember k3 1 //随机返回1个元素不删除
1) "e4"
127.0.0.1:6379> srandmember k3 1
1) "e1"
127.0.0.1:6379> srandmember k3 4
1) "e1"
2) "e4"
3) "e3"
127.0.0.1:6379> spop k3 //随机返回1个元素并删除
"e1"
127.0.0.1:6379> smembers
(error) ERR wrong number of arguments for 'smembers' command
127.0.0.1:6379> smembers k3
1) "e4"
2) "e3"
127.0.0.1:6379> spop k3 9 //3.2以后支持
(error) ERR wrong number of arguments for 'spop' command
127.0.0.1:6379>

sinter key [key...] 取交集

sunion key [key...] 取并集

sdiff key [key..] 取差集

sinterstore destination key [keys...]

union和diff同理

127.0.0.1:6379> del k1 k2 k3
(integer) 3
127.0.0.1:6379> sadd k1 1 2 3 4 5 6 7
(integer) 7
127.0.0.1:6379> sadd k2 3 4 5 6
(integer) 4
127.0.0.1:6379> sadd k3 5 6 7 8 9 10
(integer) 6
127.0.0.1:6379> sinter k1 k2
1) "3"
2) "4"
3) "5"
4) "6"
127.0.0.1:6379> sinter k1 k2 k3
1) "5"
2) "6"
127.0.0.1:6379> sinterstore k4 k1 k2 k3
(integer) 2
127.0.0.1:6379> sdiff k1 k2
1) "1"
2) "2"
3) "7"
127.0.0.1:6379> sdiff k1 k2 k3
1) "1"
2) "2"
127.0.0.1:6379> SDIFFSTORE k6 k1 k2 k3
(integer) 2
127.0.0.1:6379>

集合内部使用intset或者hashtable实现

intset为集合所有元素都为整形或者元素小于等于512个时候

hashtable为不满足intset的时候

场景

可以用于用户标签

2.6有序集合

有序集合保留了集合不能有重复元素的特征,但是可以排序,每个元素都有个对应的分数作为排序依据(分数可以重复).

zadd key score member [score member...] 添加元素

zcard key 计算元素个数

zscore key member 计算元素的分数

127.0.0.1:6379> del k1
(integer) 1
127.0.0.1:6379> zadd k1 1 e1 2 e2 3 e3 4 e4 5 e5
(integer) 5
127.0.0.1:6379> zcard k1
(integer) 5
127.0.0.1:6379> zscore k1 e3
"3"
127.0.0.1:6379>

zrank key member [member...] 和 zrevrank key member 对元素进行排序输出排序好吗,从0开始

zrem key remember [member...] 对元素进行删除

zincrby key incrememt member 增加成员的分数

127.0.0.1:6379> zrem k1 e2
(integer) 1
127.0.0.1:6379> zrank k1 e1
(integer) 0
127.0.0.1:6379> zrevrank k1 e1
(integer) 3
127.0.0.1:6379> ZINCRBY k1 99 e1
"100"
127.0.0.1:6379> zrevrank k1 e1
(integer) 0
127.0.0.1:6379> zrank k1 e1
(integer) 3
127.0.0.1:6379>

zrange key start end [withscores] 低到高排序输出start-end的元素

zrevrange key start end [withscores] 高到低排序输出元素

127.0.0.1:6379> zrange k1 0 -1 // 输出所有元素 -1是最后1个 0是第一个
1) "e3"
2) "e4"
3) "e5"
4) "e1"
127.0.0.1:6379> zrange k1 0 0
1) "e3"
127.0.0.1:6379> zrange k1 0 -3
1) "e3"
2) "e4"
127.0.0.1:6379> zrange k1 1 1
1) "e4"
127.0.0.1:6379> zrange k1 0 -1 withscores
1) "e3"
2) "3"
3) "e4"
4) "4"
5) "e5"
6) "5"
7) "e1"
8) "100"
127.0.0.1:6379> zrevrange k1 0 -1 withscores
1) "e1"
2) "100"
3) "e5"
4) "5"
5) "e4"
6) "4"
7) "e3"
8) "3"
127.0.0.1:6379>

zrangebyscore key min max [withscores] [limit offset count]

zrevrangebyscore key max min [withscores] [limit offser count]

返回指定分数范围内的成员

127.0.0.1:6379> zrange k1  0 -1 withscores
1) "e3"
2) "3"
3) "e4"
4) "4"
5) "e5"
6) "5"
7) "e1"
8) "100"
127.0.0.1:6379>
127.0.0.1:6379> zrangebyscore k1 0 999 withscores
1) "e3"
2) "3"
3) "e4"
4) "4"
5) "e5"
6) "5"
7) "e1"
8) "100"
127.0.0.1:6379> zrangebyscore k1 0 +inf withscores //+inf表示无限大
1) "e3"
2) "3"
3) "e4"
4) "4"
5) "e5"
6) "5"
7) "e1"
8) "100"
127.0.0.1:6379> zrangebyscore k1 (3 +inf withscores //默认是[闭区间 (表示开区间
1) "e4"
2) "4"
3) "e5"
4) "5"
5) "e1"
6) "100"
127.0.0.1:6379> zrangebyscore k1 {3 +inf withscores
(error) ERR min or max is not a float
127.0.0.1:6379> zrangebyscore k1 [3 +inf withscores //似乎不能是[
(error) ERR min or max is not a float
127.0.0.1:6379> zrangebyscore k1 3 -inf withscores
(empty list or set)
127.0.0.1:6379> zrangebyscore k1 3 2 withscores
(empty list or set)
127.0.0.1:6379> ZREVRANGEBYSCORE k1 +inf 0 withscores //reverse的时候先写max再写min
1) "e1"
2) "100"
3) "e5"
4) "5"
5) "e4"
6) "4"
7) "e3"
8) "3"
127.0.0.1:6379> ZREVRANGEBYSCORE k1 (100 0 withscores
1) "e5"
2) "5"
3) "e4"
4) "4"
5) "e3"
6) "3"
127.0.0.1:6379> ZREVRANGEBYSCORE k1 (100 101 withscores
(empty list or set)
127.0.0.1:6379>

zcount key min max 返回分数范围内成员个数

zremrangebyzrank key start end 删除元素,按升序

zremrangebyscore key min max 删除元素按分数

127.0.0.1:6379> zcount k1 50 +inf
(integer) 1
127.0.0.1:6379> ZRANK k1 0 -1
(error) ERR wrong number of arguments for 'zrank' command
127.0.0.1:6379> zrange k1 0 -1
1) "e3"
2) "e4"
3) "e5"
4) "e1"
127.0.0.1:6379> zrange k1 0 -1 withscores
1) "e3"
2) "3"
3) "e4"
4) "4"
5) "e5"
6) "5"
7) "e1"
8) "100"
127.0.0.1:6379> ZREMRANGEBYRANK k1 0 1
(integer) 2
127.0.0.1:6379> zrange k1 0 -1 withscores
1) "e5"
2) "5"
3) "e1"
4) "100"
127.0.0.1:6379> ZREMRANGEBYSCORE k1 0 5
(integer) 1
127.0.0.1:6379> zrange k1 0 -1 withscores
1) "e1"
2) "100"
127.0.0.1:6379>

zinterstore destnation numkeys key [key...] [weights weight [weight....]] [aggragate sum|min|max] 计算交集

127.0.0.1:6379> del k1
(integer) 1
127.0.0.1:6379> ZADD k1 10 e1 20 e2 30 e3 40 e4 50 e5
(integer) 5
127.0.0.1:6379> del k2
(integer) 1
127.0.0.1:6379> ZADD k2 11 e1 22 e2 33 e3 44 e4 55 e5
(integer) 5
127.0.0.1:6379> zadd k2 66 e6
(integer) 1
127.0.0.1:6379> ZINTERSTORE k1_2 2 k1 k2
(integer) 5
127.0.0.1:6379> zrange k1_2 0 -1
1) "e1"
2) "e2"
3) "e3"
4) "e4"
5) "e5"
127.0.0.1:6379> zrange k1_2 0 -1 withscores
1) "e1"
2) "21"
3) "e2"
4) "42"
5) "e3"
6) "63"
7) "e4"
8) "84"
9) "e5"
10) "105"
127.0.0.1:6379> ZINTERSTORE k1_2 2 k1 k2 weights 0.5 1
(integer) 5
127.0.0.1:6379> zrange k1_2 0 -1 withscores //默认是weight都是1,aggregate是sum
1) "e1"
2) "16"
3) "e2"
4) "32"
5) "e3"
6) "48"
7) "e4"
8) "64"
9) "e5"
10) "80"
127.0.0.1:6379> ZINTERSTORE k1_2 2 k1 k2 weights 0.3 //weights写了1个就必须都得写完
(error) ERR syntax error
127.0.0.1:6379> ZINTERSTORE k1_2 2 k1 k2 weights 0.3 1
(integer) 5
127.0.0.1:6379> zrange k1_2 0 -1 withscores
1) "e1"
2) "14"
3) "e2"
4) "28"
5) "e3"
6) "42"
7) "e4"
8) "56"
9) "e5"
10) "70"
127.0.0.1:6379> ZINTERSTORE k1_2 2 k1 k2 weights 0.5 0.5
(integer) 5
127.0.0.1:6379> zrange k1_2 0 -1 withscores
1) "e1"
2) "10.5"
3) "e2"
4) "21"
5) "e3"
6) "31.5"
7) "e4"
8) "42"
9) "e5"
10) "52.5"
127.0.0.1:6379> ZINTERSTORE k1_2 2 k1 k2 weights 1 1 aggragate min
(error) ERR syntax error
127.0.0.1:6379> ZINTERSTORE k1_2 2 k1 k2 weights 1 1 aggregate min
(integer) 5
127.0.0.1:6379> zrange k1_2 0 -1 withscores
1) "e1"
2) "10"
3) "e2"
4) "20"
5) "e3"
6) "30"
7) "e4"
8) "40"
9) "e5"
10) "50"
127.0.0.1:6379>

zunionstore destination numkeys key [key...] [weights weight [weight...]] [aggregate sum|min|max] 计算并集

127.0.0.1:6379> clear
127.0.0.1:6379> zrange k1 0 -1 withscores
1) "e1"
2) "10"
3) "e2"
4) "20"
5) "e3"
6) "30"
7) "e4"
8) "40"
9) "e5"
10) "50"
127.0.0.1:6379> zrange k2 0 -1 withscores
1) "e1"
2) "11"
3) "e2"
4) "22"
5) "e3"
6) "33"
7) "e4"
8) "44"
9) "e5"
10) "55"
11) "e6"
12) "66"
127.0.0.1:6379> zunoin k1_2 2 k1 k2 weights 1 0.5
(error) ERR unknown command 'zunoin'
127.0.0.1:6379> zunion k1_2 2 k1 k2 weights 1 0.5
(error) ERR unknown command 'zunion'
127.0.0.1:6379> zunionstore k1_2 2 k1 k2 weights 1 0.5
(integer) 6
127.0.0.1:6379> zrange k1_2 0 -1 WITHSCORES
1) "e1"
2) "15.5"
3) "e2"
4) "31"
5) "e6"
6) "33"    
7) "e3" //e6只有33因为k1里没有,k2 weight是0.5
8) "46.5"
9) "e4"
10) "62"
11) "e5"
12) "77.5"
127.0.0.1:6379>

内部使用ziplist和skiplist.

元素个数小于128并且只都小于64字节时用ziplist否则用skiplist

场景

主要用于排行榜

2.7键管理

rename key newKey 重命名键

renamenx key newKey  当newkey不存在的时候才会成功重命名

randomkey 随机返回1个键

127.0.0.1:6379> del k1 k2
(integer) 2
127.0.0.1:6379> mset k1 haha k2 hehe
OK
127.0.0.1:6379> mget k1 k2
1) "haha"
2) "hehe"
127.0.0.1:6379> rename k1 k2
OK
127.0.0.1:6379> exists k1
(integer) 0
127.0.0.1:6379> exists k2
(integer) 1
127.0.0.1:6379> get k2
"haha"
127.0.0.1:6379> rename k2 k2 //一样的key在3.2以下版本会boom
(error) ERR source and destination objects are the same
127.0.0.1:6379> keys *
1) "e"
2) "k2"
3) "b"
4) "k4"
5) "f"
6) "h"
7) "k6"
8) "k3"
9) "d"
10) "g"
11) "k1_2"
12) "c"
13) "a"
127.0.0.1:6379> RANDOMKEY
"k4"
127.0.0.1:6379> RANDOMKEY
"k4"
127.0.0.1:6379> RANDOMKEY
"a"
127.0.0.1:6379> RANDOMKEY
"k4"
127.0.0.1:6379> RANDOMKEY
"b"
127.0.0.1:6379>

expire key seconds 设置X秒后键过期,负数直接删除

expireat key timestamp 在秒级时间戳后x后过期

ttl key 返回键的剩余过期秒数

persist 清除键过期时间

127.0.0.1:6379> exists k2
(integer) 1
127.0.0.1:6379> ttl k2
(integer) -1 // -1不过期
127.0.0.1:6379> expire k2 999
(integer) 1
127.0.0.1:6379> ttl k2
(integer) 997
127.0.0.1:6379> PERSIST k2 //永不过期
(integer) 1
127.0.0.1:6379> ttl k2
(integer) -1
127.0.0.1:6379> get k2
"haha"
127.0.0.1:6379> del k2
(integer) 1
127.0.0.1:6379> ttl k2
(integer) -2 // -2键不存在
127.0.0.1:6379>

pexpire key milliseconds 设置键X毫秒后捡国旗

pexpireat key milliseconds-timestamp 在毫秒级时间戳X后键过期

set会去除过期时间

127.0.0.1:6379> set k1 heihei ex 999
OK
127.0.0.1:6379> get k1
"heihei"
127.0.0.1:6379> ttl k1
(integer) 994
127.0.0.1:6379> ttl k1
(integer) 993
127.0.0.1:6379> set k1 wahaha
OK
127.0.0.1:6379> ttl k1
(integer) -1 // 时间被清除了
127.0.0.1:6379>

redis不支持对二级数据结构做过期时间设置

setex命令是原子执行的

move可以在redis内部数据库进行键迁移

127.0.0.1:6379> select 0
OK
127.0.0.1:6379> get k1
"wahaha"
127.0.0.1:6379> move k1 1
(integer) 1
127.0.0.1:6379> exists k1
(integer) 0
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "k1"
127.0.0.1:6379[1]> get k1
"wahaha"
127.0.0.1:6379[1]>

dump key 将值序列化

restore key ttl value 将值反序列化到数据库中

127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> type k1
string
127.0.0.1:6379> dump l1
(nil)
127.0.0.1:6379> dump k1
"\x00\x06wahaha\x06\x00\xd7\x03\xb2\xb3I5\xd9\xc7"
127.0.0.1:6379>
127.0.0.1:6380> RESTORE k1 0 "\x00\x06wahaha\x06\x00\xd7\x03\xb2\xb3I5\xd9\xc7"
OK
127.0.0.1:6380> get k1
"wahaha"
127.0.0.1:6380>

migrate host port key| "" destination-db timeout [copy] [replace] [keys key [key ...]] 在redis之前迁移数据,migrate命令具有原子性

127.0.0.1:6379> keys *
1) "e"
2) "b"
3) "k4"
4) "k1"
5) "f"
6) "h"
7) "k6"
8) "k3"
9) "d"
10) "g"
11) "k1_2"
12) "c"
13) "a"
127.0.0.1:6379> MIGRATE localhost 6379 0 0 copy replace e b k4 k1 f h k6 k3 d g k1_2 c a
(error) ERR syntax error
127.0.0.1:6379> MIGRATE localhost 6380 0 0 copy replace e b k4 k1 f h k6 k3 d g k1_2 c a
(error) ERR syntax error
127.0.0.1:6379> MIGRATE localhost 6380 0 1000 copy replace e b k4 k1 f h k6 k3 d g k1_2 c a
(error) ERR syntax error
127.0.0.1:6379> MIGRATE 127.0.0.1 6380 0 0 copy replace e b k4 k1 f h k6 k3 d g k1_2 c a
(error) ERR syntax error
127.0.0.1:6379> MIGRATE localhost 6380 0 0 copy replace keys e b k4 k1 f h k6 k3 d g k1_2 c a
(error) ERR When using MIGRATE KEYS option, the key argument must be set to the empty string
127.0.0.1:6379> MIGRATE localhost 6380 "" 0 0 copy replace keys e b k4 k1 f h k6 k3 d g k1_2 c a //不要忘记写""
OK
127.0.0.1:6379>
127.0.0.1:6380> keys *
1) "k1_change"
127.0.0.1:6380> del k1_change
(integer) 1
127.0.0.1:6380> keys *
(empty list or set) //等待6379迁移数据过来
127.0.0.1:6380> keys *
1) "k4"
2) "c"
3) "b"
4) "k3"
5) "e"
6) "a"
7) "k6"
8) "k1_2"
9) "h"
10) "d"
11) "k1"
12) "f"
13) "g"
127.0.0.1:6380>

不知道为什么我1个redis实例不同数据库之间迁移不行,我觉得可能是因为这是1个事务,同个实例要接受迁移的键也要等这个事务结束才行.所以迁移需要等待接受好才能结束,接受需要等迁移事务结束才可以开始造成的.(猜测)

127.0.0.1:6379> MIGRATE localhost 6379 "" 1 0 copy replace keys e b k4 k1 f h k6 k3 d g k1_2 c a
(error) IOERR error or timeout reading to target instance
(1.00s)
127.0.0.1:6379> MIGRATE localhost 6379 "" 1 3000 copy replace keys e b k4 k1 f h k6 k3 d g k1_2 c a
(error) IOERR error or timeout reading to target instance
(3.00s)
127.0.0.1:6379>

迁移命令比较

命令 作用域 原子性 支持多个键
move redis实例内部
dump+restore redis实例之间
migrate redis实例之间

  

keys pattern 遍历键

*代表任意字符

?代表一个字符

[]代表部分匹配,[1,3]代表匹配1,3 [1-10]代表匹配1-10任意数字

\x用来转义

127.0.0.1:6380> exists ka1
(integer) 1
127.0.0.1:6380> keys k[a-z]1
1) "ka1"
127.0.0.1:6380> k?[1-99]
(error) ERR unknown command 'k?[1-99]'
127.0.0.1:6380> k?[0-10]
(error) ERR unknown command 'k?[0-10]'
127.0.0.1:6380> k?[1-10]
(error) ERR unknown command 'k?[1-10]'
127.0.0.1:6380> keys k?[0-99]
1) "ka1"
127.0.0.1:6380>

删除键

redis-cli keys pattern | xargs redis-cli del //我执行是失败的,不认识xargs....

渐进式遍历键

scan cursor [match pattern] [count number]

cursor是游标,从0开始,count number默认是10,命令返回当前游标值

127.0.0.1:6380> mset a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q qr r s s t t u u v v w w x x y y z z
(error) ERR wrong number of arguments for MSET
127.0.0.1:6380> mset a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q q r r s s t t u u v v w w x x y y z z
OK
127.0.0.1:6380> scan 0
1) "22"
2) 1) "y"
2) "g"
3) "o"
4) "z"
5) "s"
6) "e"
7) "i"
8) "h"
9) "a"
10) "t"
127.0.0.1:6380> scan 22
1) "7"
2) 1) "b"
2) "j"
3) "k"
4) "q"
5) "d"
6) "m"
7) "r"
8) "n"
9) "p"
10) "x"
11) "f"
127.0.0.1:6380> scan 7
1) "0"
2) 1) "v"
2) "l"
3) "u"
4) "w"
5) "c"
127.0.0.1:6380>

注意第二次返回了11个元素

SCAN 命令的保证(guarantees)

SCAN 命令, 以及其他增量式迭代命令, 在进行完整遍历的情况下可以为用户带来以下保证: 从完整遍历开始直到完整遍历结束期间, 一直存在于数据集内的所有元素都会被完整遍历返回; 这意味着, 如果有一个元素, 它从遍历开始直到遍历结束期间都存在于被遍历的数据集当中, 那么 SCAN 命令总会在某次迭代中将这个元素返回给用户。

然而因为增量式命令仅仅使用游标来记录迭代状态, 所以这些命令带有以下缺点:

  • 同一个元素可能会被返回多次。 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上。
  • 如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会, 这是未定义的(undefined)。

SCAN 命令每次执行返回的元素数量

增量式迭代命令并不保证每次执行都返回某个给定数量的元素。

增量式命令甚至可能会返回零个元素, 但只要命令返回的游标不是 0 , 应用程序就不应该将迭代视作结束。

不过命令返回的元素数量总是符合一定规则的, 在实际中:

  • 对于一个大数据集来说, 增量式迭代命令每次最多可能会返回数十个元素;
  • 而对于一个足够小的数据集来说, 如果这个数据集的底层表示为编码数据结构(encoded data structure,适用于是小集合键、小哈希键和小有序集合键), 那么增量迭代命令将在一次调用中返回数据集中的所有元素。

最后, 用户可以通过增量式迭代命令提供的 COUNT 选项来指定每次迭代返回元素的最大值。

COUNT 选项

虽然增量式迭代命令不保证每次迭代所返回的元素数量, 但我们可以使用 COUNT 选项, 对命令的行为进行一定程度上的调整。

基本上, COUNT 选项的作用就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素。

虽然 COUNT 选项只是对增量式迭代命令的一种提示(hint), 但是在大多数情况下, 这种提示都是有效的。

  • COUNT 参数的默认值为 10 。
  • 在迭代一个足够大的、由哈希表实现的数据库、集合键、哈希键或者有序集合键时, 如果用户没有使用 MATCH 选项, 那么命令返回的元素数量通常和 COUNT 选项指定的一样, 或者比 COUNT 选项指定的数量稍多一些。
  • 在迭代一个编码为整数集合(intset,一个只由整数值构成的小集合)、 或者编码为压缩列表(ziplist,由不同值构成的一个小哈希或者一个小有序集合)时, 增量式迭代命令通常会无视 COUNT 选项指定的值, 在第一次迭代就将数据集包含的所有元素都返回给用户。

并非每次迭代都要使用相同的 COUNT 值。

用户可以在每次迭代中按自己的需要随意改变 COUNT 值, 只要记得将上次迭代返回的游标用到下次迭代里面就可以了。

http://doc.redisfans.com/key/scan.html

select index 切换数据库

建议使用多个实例,只是用数据库0.因为1个实例多个数据库也是共享1个CPU的.

flushdb 清除当前数据库数据

flushall 清除所有数据库数据

redis 开发与运维 学习心得1的更多相关文章

  1. Redis开发与运维学习笔记

    <Redis开发与运维>读书笔记   一.初始Redis 1.Redis特性与优点 速度快.redis所有数据都存放于内存:是用C语言实现,更加贴近硬件:使用了单线程架构,避免了多线程竞争 ...

  2. Redis开发与运维:SDS

    STRING 我们会经常打交道的string类型,在redis中拥有广泛的使用.也是开启redis数据类型的基础. 在我最最开始接触的redis的时候,总是以为字符串类型就是值的类型是字符串. 比如: ...

  3. Redis实战(七)Redis开发与运维

    Redis用途 1.缓存 Redis提供了键值过期时间设置, 并且也提供了灵活控制最大内存和内存溢出后的淘汰策略. 可以这么说, 一个合理的缓存设计能够为一个网站的稳定保驾护航. 2.排行榜系统 Re ...

  4. Redis 开发与运维

    Getting Start 高性能 性能优势的体现 C语言实现的内存管理 epoll的I/O多路复用技术+IO连接/关闭/读写通过事件实现异步的非阻塞IO TCP协议 单线程架构,不会因为高并发对服务 ...

  5. 《Redis开发与运维》快速笔记(一)

    1.前言&基本介绍 在原始的系统架构中,我们都由程序直接连接DB,随着业务的进一步开展,DB的压力越来越大,为了缓解DB的这一压力,我们引入了缓存,在程序连接DB中加入缓存层, 从而减轻数据库 ...

  6. 《Redis开发与运维》

    第1章 初识Redis 1. Redis介绍: Redis是一种基于键值对(key-value)的NoSQL数据库. 与很多键值对数据库不同的是,Redis中的值可以是由string(字符串).has ...

  7. 《Redis开发与运维》读书笔记

    一.初始Redis 1.Redis特性与优点 速度快.redis所有数据都存放于内存:是用C语言实现,更加贴近硬件:使用了单线程架构,避免了多线程竞争问题 基于键值对的数据结构,支持的数据结构丰富.它 ...

  8. Redis开发与运维

    常用命令 redis-server启动redis redis-server /opt/redis/redis.conf    配置启动 redis-server --port 6379 --dir / ...

  9. Redis开发与运维:linux安装

    Linux 安装 我的系统是inux 系统,官网下载 https://redis.io/download redis-5.0.5.tar.gz 解压: 编译安装: 官网和文档说得已经很清楚了,现在就执 ...

随机推荐

  1. BZOJ3566 SHOI2014 概率充电器 【概率DP】

    BZOJ3566 SHOI2014 概率充电器 Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器: “采用全新纳米级加工技术,实现元件与导线能 ...

  2. 【DUBBO】Dubbo原理解析-Dubbo内核实现之SPI简单介绍

    Dubbo采用微内核+ 插件体系,使得设计优雅,扩展性强.那所谓的微内核+插件体系是如何实现的呢!大家是否熟悉spi(service providerinterface)机制,即我们定义了服务接口标准 ...

  3. vue-router教程二(要素篇之新手入门)

    注意,我们将在指南中使用es 2015代码样本.此外,所有示例都将使用VUE的完整版本来使在线模板编译成为可能.请参阅这里的更多细节. 用vue路由器创建单页应用程序是非常简单的.使用vue.js,我 ...

  4. linux 磁盘挂载操作

    1. fdisk  -l      查看磁盘   2. fisk  /dev/vdb   进行分区        依次输入  n  p  1   两次回车  wq   3. fdisk -l  查看分 ...

  5. Mysql 5.7初始化密码

    一.MAC Mysql安装 1.下载dmg安装 从http://dev.mysql.com/downloads/mysql/下载dmg安装 二.Mysql密码修改 1.通过mysql -uroot - ...

  6. oracle 之 手动建库

    1.-- 查看服务器 ORA 环境变量情况[oracle@orastb ~]$ env|grep ORAORACLE_BASE=/u01/app/oracleORACLE_HOME=/u01/app/ ...

  7. Android 从上层到底层-----hal层

    CPU:RK3288 系统:Android 5.1 功能:上层 app 控制 led 亮灭 开发板:Firefly RK3288 led_hal.c path:hardware/rockchip/fi ...

  8. Nginx+jwPlay搭建流媒体服务器,记忆播放

    1.具体的流媒体服务器的搭建参考博客: http://blog.chinaunix.net/uid-20639775-id-154556.html 具体可能编译的时候有个地方报错 /root/ngin ...

  9. 数据结构与算法JavaScript描述——使用队列

    1.使用队列:方块舞的舞伴分配问题 前面我们提到过,经常用队列模拟排队的人.下面我们使用队列来模拟跳方块舞的人.当 男男女女来到舞池,他们按照自己的性别排成两队.当舞池中有地方空出来时,选两个队 列中 ...

  10. mysql字符集和校对规则(Mysql校对集)

    字符集的概念大家都清楚,校对规则很多人不了解,一般数据库开发中也用不到这个概念,mysql在这方便貌似很先进,大概介绍一下简要说明 字符集和校对规则 字符集是一套符号和编码.校对规则是在字符集内用于比 ...