主要是命令相关
第一章 初识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:6379> set k1 abc //set设置值 OK 127.0.0.1:6379> set k2 def ex 999 //ex设置过期秒数,px设置毫秒数 OK 127.0.0.1:6379> ttl k2 (integer) 997 127.0.0.1:6379> set k1 change xx // xx key 存在才更新不然不操作,用于更新 OK 127.0.0.1:6379> get k1 "change" 127.0.0.1:6379> set k1 qqq OK 127.0.0.1:6379> get k1 "qqq" 127.0.0.1:6379> ttl k2 (integer) 957 127.0.0.1:6379> set k3 ttt nx // nx key 不存在才操作,用于插入 OK 127.0.0.1:6379> get k3 "ttt" 127.0.0.1:6379> set k3 www xx OK 127.0.0.1:6379> get k3 "www" 127.0.0.1:6379> set k3 ppp nx // 不存在key,用nx操作. (nil) 127.0.0.1:6379> 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 清除所有数据库数据