前一篇入口:redis 入门-1
1. string
字符串是 redis 中最基础的数据类型。
(1)redis 中所有键都是 string 类型,其它几种数据结构均在字符串类似基础上构建
(2)字符串类型的值可以是 字符串(一般字符串或JSON,XML等格式的字符串),数字(int 或 float),二进制流数据(如图片,音频,视频等;但是一个字符串最大不超 512MB)
(3)redis 按二进制流保存 字符串,故不涉及字符集编码问题,传入什么编码,就存什么编码
1.1 基本命令
1.1.1 set
设置 key 的 value,如已存在,则覆盖。之前在该 key 上的 ttl 也失效。
返回值 OK:成功, nil:失败
时间复杂度:O(1)
bash
SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
ex : seconds 秒为单位的过期时间,
px : milliseconds 毫米单位过期时间,
nx : 不存在则设置,反之不执行,
xx: 存在则设置,反之不执行
setnx , setex , psetex 等带要求的 set 可以由这些替代
1.1.2 get
获取key对应的 value,
返回值: key存在返对应value,key不存则返 nil
时间复杂度:O(1)
bash
GET key
1.1.3 mget
一次得多个 value,
返回值: key存在返对应value,key不存或不是string类型则返 nil
时间复杂度:O(N) N 是 key 数量
bash
MGET key [key ...]
1.1.4 mset
一次设置多个 key 的值,
返回值:OK
时间复杂度:O(N) N 是 key 数量
bash
MSET key value [key value ...]
相较于多个key 多次get/set 要经历多次网络传输,
而 mset/mget 之经历一次网络传输。
一定范围内(无节制的话会导致,redis堵塞)用 mset/ mget 批量处理,效率更高。
1.1.5 incr
value 是整型则加一 ,不是整型或超出64位有符号整型 则报错,不存则创建(初始值为 0),
返回最终值
时间复杂度:O(1)
bash
INCR key

1.1.6 incrby
value 是整型则加指定数值 ,不是整型或超出64位有符号整型 则报错,不存则创建(初始值为 0),
返回最终值
时间复杂度:O(1)
bash
INCRBY key decrement

1.1.7 decr
value 是整型则减一,不是整型或超出64位有符号整型则报错,不存则创建(初始值为 0);
返回最终值
时间复杂度:O(1)
bash
DECR key
1.1.8 decrby
value 是整型则减指定数值,不是整型或超出64位有符号整型则报错,不存则创建(初始值为 0);
返回最终值
时间复杂度:O(1)
bash
DECRBY key decrement
1.1.9 incrbyfloat
value 是浮点数则加指定值 ,不是string 或 不是浮点则报错,不存则创建(初始值为 0),
返最终值。
加的这个值允许用科学计数法表示
时间复杂度:O(1)
bash
INCRBYFLOAT key increment

1.1.10 append
key存在则追加,不存则创建,返回字符串总长。
时间复杂度:O(1),追加的字符串⼀般较短, 可以视为 O(1)。
bash
APPEND KEY VALUE

1.1.11 getrange
bash
GETRANGE key start end
取子串,左闭右闭,下标从 0 算。可以用负数表示倒着来,eg:-1 即倒数第一个字符。 如果超出 string 长度则自动取正确的值,返回子串
时间复杂度:O(N),N 为 [start, end] 区间的长度。由于 string 通常较短,可以视为是 O(1)

1.1.12 setrange
bash
SETRANGE key offset value
覆盖子串,从指定的偏移开始,下标从 0 开始计算
时间复杂度:O(N),N 为 value的长度。由于 value 通常较短,可以视为是 O(1)

1.1.13 strlen
bash
STRLEN key
得字符串长度,不是 string 则报错
时间复杂度:O(1)

1.2 内部编码
字符串内部编码:
- int:8字节长整型
- embstr:小于等于39字节 字符串
- raw :大于39字节字符串
redis 会根据当前值的类型和长度动态选择用哪种编码
1.3 常见使用场景
- 缓存
用 string 类型存储信息,当作缓存。 - 计数
例如:视频播放次数可以用 redis 实现,视频放一次,对应播放数 +1 - 共享会话
用户的请求会经负载均衡后,会均匀发给各个服务器,这存在上一请求刚在一个服务器上保存了session信息(如登录信息),下一个请求到了另一台上,没有用户信息要重新登录的问题。
可以用 redis 集中管理 session信息,服务器从 redis 中查询,更新 session信息。 - 手机验证码
redis设置过期时间,记录发送次数。
2. Hash
redis 中 hash 是 key-value 中的 value 又是一个键值对结构。
可以将 key 看作是 哈希表的表名,value 是哈希表的内容。
由于 redis 本身使用键值对存储数据(key-value),为了作区分,hash 类型中的映射关系为 field-value
2.1 基本命令
2.1.1 HSET & HGET
hset 设置hash中字段field 的 值value
返回值为添加的字段的个数
时间复杂度:插入一组 field 为 O(1),插入 N 组 field 为 O(N)
bash
HSET key field value [field value ...]
hget 拿hash中 字段的值
返回字段值 或 nil
时间复杂度: O(1)
bash
HGET key field
shell
127.0.0.1:6379> HSET myhash field1 "hello"
1
127.0.0.1:6379> HGET myhash field1
hello
2.1.2 HEXISTS & HDEL
bash
HEXISTS key field
HDEL key field [field ...]
hexists 判断hash中是否存在指定字段 返回 1:存在,0:不存
时间复杂度: O(1)
hdel 删除hash中的字段,返回删除的字段个数
时间复杂度: O(N),N为元素个数
bash
127.0.0.1:6379> HEXISTS myhash field1
1
127.0.0.1:6379> HEXISTS myhash field2
0
127.0.0.1:6379> HSET myhash field2 "world"
1
127.0.0.1:6379> HGET myhash field2
world
127.0.0.1:6379> HDEL myhash field2
1
2.1.3 HKEYS & HVALS
bash
HKEYS key
HVALS key
hkeys 获取hash中所有字段 返回字段列表
时间复杂度: O(N),N为field个数
hvals 获取hash中所有字段的值,返回所有的值
时间复杂度: O(N),N为field个数
bash
127.0.0.1:6379> HSET myhash field2 "world"
1
127.0.0.1:6379> HKEYS myhash
field1
field2
127.0.0.1:6379> HVALS myhash
hello
world
2.1.4 HGETALL
bash
HGETALL key
hgetall 获取hash中所有字段及其对应的值 返回字段和对应值
时间复杂度: O(N),N为field个数
bash
127.0.0.1:6379> HGETALL myhash
field1
hello
field2
world
2.1.5 HMGET
bash
HMGET key field [field ...]
HMGET 一次得多个字段的值 返回 值或nil
时间复杂度: O(N),N为元素个数
bash
127.0.0.1:6379> HMGET myhash field1 field2
hello
world
2.1.6 HLEN
bash
HLEN key
HLEN hash中字段个数 返字段个数
时间复杂度: O(1)
bash
127.0.0.1:6379> HLEN myhash
2
2.1.7 HSETNX
bash
HSETNX key field value
HSETNX 不存,则设置对应字段和值 返1:成功,0:失败
时间复杂度: O(1)
bash
127.0.0.1:6379> HSETNX myhash field3 "你好"
1
127.0.0.1:6379> HSETNX myhash field3 20
0
2.1.8 HINCRBY
bash
HINCRBY key field increment
HINCRBY hash中字段对应值加指定数值 返最终值
时间复杂度: O(1)
bash
127.0.0.1:6379> HSET myhash field3 20
0
127.0.0.1:6379> HINCRBY myhash field3 16
36
2.1.9 HINCRBYFLOAT
bash
HINCRBYFLOAT key field increment
HINCRBYFLOAT hash中字段对应值加指定浮点数 返最终值
时间复杂度: O(1)
bash
127.0.0.1:6379> hget myhash field4
20
127.0.0.1:6379> HINCRBYFLOAT myhash field4 16.0
36
127.0.0.1:6379> HINCRBYFLOAT myhash field4 -0.3
35.7
2.2 内部编码
hash 内部编码有两种:
- ziplist(压缩链表):哈希类型元素个数小于
hash-max-ziplist-entries配置(默认512个),且所有值小于hash-max-ziplist-value配置(默认64个字节)时用 ziplist。ziplist 多元素连续存储的实现结构更紧凑,较 hashtable 省内存。 - hashtable(哈希表):不满足ziplist时,用 hashtable 作底层实现,因此时 ziplist 读写效率会下降,而 hashtable 的读写时复为 O(1)
2.3 使用场景
- 保存用户信息
相比于 JSON格式的字符串缓存用户信息,hash 类型更直观,且在更新上更灵活。
哈希类型和关系型数据库的不同
- 哈希类型时稀疏的,关库是完全结构化的,eg:hash 类型每个键可有不同的field,而关库加了新列,其他行都有为其设值
- 关库可做复杂的关系查询,而 redis 模拟关系型复杂查询,如:联表查询,聚合查询等基本不可能,维护成本高
- 缓存方式对比
- 直接存字符串,每个属性一个键
bash
set user:1:name James
set user:1:age 23
set user:1:city Beijing
优:简单,针对单个属性的变更灵活
缺:占用过多键,内存占用大;同时信息分散,内聚性低;基本没有实用性
- 序列化字符串类型,如 JSON 格式
bash
set user:1 经过序列化后的⽤⼾对象字符串
优:针对整体操作的信息合适,编程简单;序列化方案选择合适,内存利用率高
缺:序列化和反序列化有一定开销,针对单个属性的操作不灵活
- 哈希类型
bash
mset user:1 name James age 23 city Beijing
优:简单,直观,灵活,特别是针对信息的局部变更或获取
缺:要控制哈希在 ziplist 和 hashtable 内部编码间的转换,可能造成内存消耗大
3. List
列表类型用于存储多个有序字符串,列表中每个字符串称为元素,最多可存 2^32 - 1 个元素。
list 中元素有序,可通过下标获取某一元素或某个范围的元素列表。
下标:
- 从左到右:0,1,2,......
- 从右向左:-1,-2,-3,......
3.1 基本命令
3.1.1 LPUSH
bash
LPUSH key element [element ...]
将一个/多个元素从左侧插入 list
返:插入后list 长度
bash
127.0.0.1:6379> LPUSH mylist "world"
1
127.0.0.1:6379> LPUSH mylist "hellow"
2
127.0.0.1:6379> LRANGE mylist 0 -1
hellow
world
3.1.2 LPUSHX
bash
LPUSHX key element [element ...]
可以存在则从左插入list,不存在,则直接返回
返:插入后的长度
bash
127.0.0.1:6379> LPUSHX mylist2 "HELLO"
0
127.0.0.1:6379> LPUSHX mylist "888888"
5
3.1.3 RPUSH,RPUSHX
同 LPUSH,RPUSHX,但右侧插入。
3.1.4 LRANG
bash
LRANGE key start stop
获得指定范围元素,左闭右闭。
返:指定区间元素
bash
127.0.0.1:6379> LRANGE mylist 0 -1
HELLOW
WORLD
and
hellow
world
3.1.5 LPOP/RPOP
bash
LPOP key
从list左/右侧侧取出元素(头/尾删)
返:取出的元素 或 nil
bash
127.0.0.1:6379> LPOP mylist
888888
3.1.6 LINDEX
bash
LINDEX key index
获取从左数地 index 位置元素
返:元素 或 nil
bash
127.0.0.1:6379> LINDEX mylist 2
hellow
3.1.7 LINSERT
bash
LINSERT key <BEFORE | AFTER> pivot element
指定位置插入元素
返:插入和长度
bash
127.0.0.1:6379> LRANGE mylist 0 -1
HELLOW
WORLD
hellow
world
127.0.0.1:6379> LINSERT mylist BEFORE "hellow" "and"
5
127.0.0.1:6379> LRANGE mylist 0 -1
HELLOW
WORLD
and
hellow
world
3.1.8 LLEN
bash
LLEN key
获取 list 长度
返:长度
bash
127.0.0.1:6379> LLEN mylist
5
3.1.9 BLPOP/BRPOP
bash
BLPOP key [key ...] timeout
LPOP 和 RPOP 的阻塞版本
list 有元素时,阻塞与非阻塞表现一致;
没有元素时,非阻塞直接返 nil,而阻塞则根据 timeout (单位为秒),阻塞一段时间,期间有元素存入,则取出,若到了 timeout,还没有则返回 nil。
阻塞期间,redis 可以执行其他命令,但执行该命令的客户端会表现为阻塞状态
如果多个客户端同时都对一个 key 执行 阻塞pop,先执行的先得元素。
bash
127.0.0.1:6379> EXISTS mylist mylist2
1
127.0.0.1:6379> BLPOP mylist mylist2 10
mylist
HELLOW
3.2 内部编码
- ziplist(压缩链表) :列表元素个数小于
hash-max-ziplist-entries配置(默认512个),且所有值小于hash-max-ziplist-value配置(默认64个字节)时用 ziplist。ziplist 多元素连续存储的实现结构更紧凑,省内存 - linkedlist(链表):不满足ziplist要求,则用 linkedlist
3.3 使用场景
- 消息队列
lpush + brpop 实现经典的阻塞式生产者-消费者模型队列,⽣产者客户端 lpush 从左侧插入元素,多个消费者客户端 brpop 阻塞式地从队列中取元素。 - 微博 Timeline
- 同侧存取:栈;异侧:队列