Redis学习笔记:含数据类型常用操作命令、事务、持久化等

典型应用场景

  • 缓存系统
    可以用string实现
  • 计数器
    有incr命令,可在单线程下进行非常高效的计数,且不会出现计数错误的问题,比如微博转发、评论的计数。
    可以用string实现
  • 购物车
    可以用hash实现
  • 排行榜
    可以用有序集合实现
  • 消息队列
    可以用列表实现
  • 活动秒杀

一些基础知识

单线程

Redis一次只运行一条命令。但在做一些文件操作时不是单线程的,比如fysnc file descriptor。
单线程速度还快的原因如下:

  • 纯内存 (本质)
  • 非阻塞IO(IO多路复用) ,不在IO上浪费过多的时间(辅)
  • 避免线程切换和竞态消耗(要知道对多线成使用不合理时,甚至会比单线程慢)(辅)

数据类型内部编码

数据类型 内部编码
string raw、int、embstr
hash hashtable、ziplist
list linkedlist、ziplist
set hashtable、intset
zset skiplist、ziplist

数据库操作常用命令

默认16个数据库,类似数组下表从零开始,初始默认使用0号库。
数据库操作相关命令如下所示:

命令 语法 作用 返回值
EXISTS EXISTS key 检查给定 key 是否存在 key 存在,返回 1 ,否则返回 0
TYPE TYPE key 返回 key 所储存的值的类型 none (key不存在)、string、list、hash、set、zset、stream
MOVE MOVE key 将当前数据库的 key 移动到给定的数据库 db 当中 移动成功返回 1 ,失败则返回 0
DEL DEL key 删除给定的一个或多个 key 。不存在的 key 会被忽略 被删除 key 的数量
DBSIZE DBSIZE key 返回当前数据库的 key 的数量 当前数据库的 key 的数量
KEYS KEYS pattern 查找所有符合给定模式 pattern 的 key,例如keys *(匹配数据库中所有key)、KEYS t*est (匹配 test和 taaaest)等.特殊符号用 \ 隔开 符合给定模式的 key 列表
FLUSHDB FLUSHDB 清空当前数据库中的所有 key 总是返回 OK
FLUSHALL FLUSHALL 清空整个 Redis 服务器的数据(删除所有数据库的所有 key ) 总是返回 OK
SELECT SELECT index 切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值 总是返回 OK

数据类型

字符串(string)

特点

  • string是 Redis 最基本的类型,一个 key 对应一个 value
  • string是二进制安全的,也就是可以包含任何数据,比如jpg图片或者序列化的对象
  • string最大能存储 512MB

常用命令

SET
  • 语法
    SET key value

  • 说明
    将字符串值 value 关联到 key 。如果 key 已经持有其他值, SET 就覆写旧值, 无视类型。当 SET 命令对一个带有生存时间(TTL)的键进行设置之后, 该键原有的 TTL 将被清除。

  • 相关案例
    正常设置值:

    1
    2
    3
    4
    redis 127.0.0.1:6379> SET key "test"
    OK
    redis 127.0.0.1:6379> GET key
    "test"

    使用 EX 选项:

    1
    2
    3
    4
    5
    6
    7
    8
    redis 127.0.0.1:6379> SET key-with-expire-time "hello" EX 10086
    OK

    redis 127.0.0.1:6379> GET key-with-expire-time
    "hello"

    redis 127.0.0.1:6379> TTL key-with-expire-time
    (integer) 10069
GET
  • 语法
    GET key

  • 说明
    返回与键 key 相关联的字符串值。

  • 返回值
    如果键 key 不存在, 那么返回特殊值 nil ; 否则, 返回键 key 的值。如果键 key 的值并非字符串类型, 那么返回一个错误, 因为 GET 命令只能用于字符串 值。

  • 相关案例
    对不存在的键 key 或是字符串类型的键 key 执行 GET 命令:

    1
    2
    3
    4
    5
    6
    redis> GET db
    (nil)
    redis> SET db redis
    OK
    redis> GET db
    "redis"

    对不是字符串类型的键 key 执行 GET 命令:

    1
    2
    3
    4
    5
    redis> LPUSH db redis mongodb mysql
    (integer) 3

    redis> GET db
    (error) ERR Operation against a key holding the wrong kind of value
INCR
  • 语法
    INCR key

  • 说明
    为键 key 储存的数字值加上1。如果键 key 不存在, 那么它的值会先被初始化为 0 , 然后再执行 INCR 命令。如果键 key 储存的值不能被解释为数字, 那么 INCR 命令将返回一个错误。

  • 返回值
    INCR 命令会返回键 key 在执行加一操作之后的值。

  • 相关案例

    1
    2
    3
    4
    5
    6
    redis> SET page_view 20
    OK
    redis> INCR page_view
    (integer) 21
    redis> GET page_view # 数字值在 Redis 中以字符串的形式保存
    "21"
INCRBY
  • 语法
    INCRBY key increment

  • 说明
    为键 key 储存的数字值加上增量 increment 。如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 INCRBY 命令。如果键 key 储存的值不能被解释为数字, 那么 INCRBY 命令将返回一个错误。

  • 返回值
    在加上增量 increment 之后, 键 key 当前的值。

  • 相关案例
    键存在,并且值为数字:

    1
    2
    3
    4
    5
    6
    redis> SET rank 50
    OK
    redis> INCRBY rank 20
    (integer) 70
    redis> GET rank
    "70"

    键不存在:

    1
    2
    3
    4
    5
    6
    7
    8
    redis> EXISTS counter
    (integer) 0

    redis> INCRBY counter 30
    (integer) 30

    redis> GET counter
    "30"

    键存在,但值无法被解释为数字:

    1
    2
    3
    4
    redis> SET book "long long ago..."
    OK
    redis> INCRBY book 200
    (error) ERR value is not an integer or out of range
DECR
  • 语法
    DECR key

  • 说明
    为键 key 储存的数字值减去一。如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECR 操作。如果键 key 储存的值不能被解释为数字, 那么 DECR 命令将返回一个错误。

  • 返回值
    DECR 命令会返回键 key 在执行减一操作之后的值。

  • 相关案例
    对储存数字值的键 key 执行 DECR 命令:

    1
    2
    3
    4
    redis> SET test 10
    OK
    redis> DECR test
    (integer) 9

    对不存在的键执行 DECR 命令:

    1
    2
    3
    4
    redis> EXISTS count
    (integer) 0
    redis> DECR count
    (integer) -1
DECRBY
  • 语法
    DECRBY key decrement

  • 说明
    将键 key 储存的整数值减去减量 decrement 。如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECRBY 命令。如果键 key 储存的值不能被解释为数字, 那么 DECRBY 命令将返回一个错误。

  • 返回值
    DECRBY 命令会返回键在执行减法操作之后的值。

  • 相关案例
    对已经存在的键执行 DECRBY 命令:

    1
    2
    3
    4
    redis> SET count 100
    OK
    redis> DECRBY count 20
    (integer) 80

    对不存在的键执行 DECRBY 命令:

    1
    2
    3
    4
    redis> EXISTS pages
    (integer) 0
    redis> DECRBY pages 10
    (integer) -10
MSET
  • 语法
    MSET key value [key value …]

  • 说明
    同时为多个键设置值。如果某个给定键已经存在, 那么 MSET 将使用新值去覆盖旧值, 如果这不是你所希望的效果, 请考虑使用 MSETNX 命令, 这个命令只会在所有给定键都不存在的情况下进行设置。

  • 返回值
    总是返回 OK 。

  • 相关案例
    同时对多个键进行设置:

    1
    2
    3
    4
    5
    6
    7
    redis> MSET date "2012.3.30" time "11:00 a.m." weather "sunny"
    OK

    redis> MGET date time weather
    1) "2012.3.30"
    2) "11:00 a.m."
    3) "sunny"

    覆盖已有的值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    redis> MGET k1 k2
    1) "hello"
    2) "world"

    redis> MSET k1 "good" k2 "bye"
    OK

    redis> MGET k1 k2
    1) "good"
    2) "bye"
MGET
  • 语法
    MGET key [key …]

  • 说明
    返回给定的一个或多个字符串键的值。如果给定的字符串键里面, 有某个键不存在, 那么这个键的值将以特殊值 nil 表示。

  • 返回值
    MGET 命令将返回一个列表, 列表中包含了所有给定键的值。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    redis> SET baidu  baidu.com
    OK

    redis> SET google google.com
    OK

    redis> MGET baidu google
    1) "baidu.com"
    2) "google.com"

    redis> MGET baidu google mysql # 不存在的 mysql 返回 nil
    1) "baidu.com"
    2) "google.com"
    3) (nil)

哈希表(hash)

特点

  • hash是一个键值(key=>value)对集合
  • hash特别适合用于存储对象

常用命令

HSET
  • 语法
    HSET hash field value

  • 说明
    将哈希表 hash 中域 field 的值设置为 value 。如果给定的哈希表并不存在, 那么一个新的哈希表将被创建并执行 HSET 操作。如果域 field 已经存在于哈希表中, 那么它的旧值将被新值 value 覆盖。

  • 返回值
    当 HSET 命令在哈希表中新创建 field 域并成功为它设置值时, 命令返回 1 ; 如果域 field 已经存在于哈希表, 并且 HSET 命令成功使用新值覆盖了它的旧值, 那么命令返回 0 。

  • 相关案例
    设置一个新域:

    1
    2
    3
    4
    5
    redis> HSET website baidu "www.baidu.org"
    (integer) 1

    redis> HGET website baidu
    "www.baidu.org"

    对一个已存在的域进行更新:

    1
    2
    3
    4
    5
    redis> HSET website baidu "www.baidu.com"
    (integer) 0

    redis> HGET website baidu
    "www.baidu.com"
HGET
  • 语法
    HGET hash field

  • 说明
    返回哈希表中给定域的值。如果给定域不存在于哈希表中, 又或者给定的哈希表并不存在, 那么命令返回 nil 。

  • 返回值
    返回哈希表中给定域的值。

  • 相关案例
    域存在的情况:

    1
    2
    3
    4
    5
    redis> HSET website baidu "www.baidu.org"
    (integer) 1

    redis> HGET website baidu
    "www.baidu.org"

    域不存在情况:

    1
    2
    redis> HGET website mysql 
    (nil)
HSETNX
  • 语法
    HSETNX hash field value

  • 说明
    当且仅当域 field 尚未存在于哈希表的情况下, 将它的值设置为 value 。如果给定域已经存在于哈希表当中, 那么命令将放弃执行设置操作。如果哈希表 hash 不存在, 那么一个新的哈希表将被创建并执行 HSETNX 命令。

  • 返回值
    HSETNX 命令在设置成功时返回 1 , 在给定域已经存在而放弃执行设置操作时返回 0 。

  • 相关案例
    域尚未存在, 设置成功:

    1
    2
    3
    4
    5
    redis> HSETNX database key-value-store Redis
    (integer) 1

    redis> HGET database key-value-store
    "Redis

    域已经存在, 设置未成功, 域原有的值未被改变:

    1
    2
    3
    4
    5
    redis> HSETNX database key-value-store Riak
    (integer) 0

    redis> HGET database key-value-store
    "Redis"
HEXISTS
  • 语法
    HEXISTS hash field

  • 说明
    检查给定域 field 是否存在于哈希表 hash 当中。

  • 返回值
    HEXISTS 命令在给定域存在时返回 1 , 在给定域不存在时返回 0 。

  • 相关案例
    给定域不存在:

    1
    2
    redis> HEXISTS phone myphone
    (integer) 0

    给定域存在:

    1
    2
    3
    4
    5
    redis> HSET phone myphone nokia-1110
    (integer) 1

    redis> HEXISTS phone myphone
    (integer) 1
HLEN
  • 语法
    HLEN key

  • 说明
    返回哈希表 key 中域的数量。

  • 返回值
    哈希表中域的数量。当 key 不存在时,返回 0 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    redis> HSET db redis redis.com
    (integer) 1

    redis> HSET db baidu baidu.com
    (integer) 1

    redis> HLEN db
    (integer) 2

    redis> HSET db google google.com
    (integer) 1

    redis> HLEN db
    (integer) 3
HDEL
  • 语法
    HDEL key field [field …]

  • 说明
    删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。

  • 返回值
    被成功移除的域的数量,不包括被忽略的域。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #测试数据
    redis> HGETALL abbr
    1) "a"
    2) "apple"
    3) "b"
    4) "banana"
    5) "c"
    6) "cat"
    7) "d"
    8) "dog"

    # 删除单个域
    redis> HDEL abbr a
    (integer) 1

    # 删除不存在的域
    redis> HDEL abbr not-exists-field
    (integer) 0

    # 删除多个域
    redis> HDEL abbr b c
    (integer) 2
    redis> HGETALL abbr
    1) "d"
    2) "dog"

HKEYS
  • 语法
    HKEYS key

  • 说明
    返回哈希表 key 中的所有域。

  • 返回值
    一个包含哈希表中所有域的表。当 key 不存在时,返回一个空表。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 哈希表非空
    redis> HMSET website google www.google.com yahoo www.yahoo.com
    OK
    redis> HKEYS website
    1) "google"
    2) "yahoo"

    # 空哈希表/key不存在
    redis> EXISTS fake_key
    (integer) 0

    redis> HKEYS fake_key
    (empty list or set)
HVALS
  • 语法
    HVALS key

  • 说明
    返回哈希表 key 中所有域的值。

  • 返回值
    一个包含哈希表中所有值的表。当 key 不存在时,返回一个空表。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 非空哈希表
    redis> HMSET website google www.google.com yahoo www.yahoo.com
    OK
    redis> HVALS website
    1) "www.google.com"
    2) "www.yahoo.com"

    # 空哈希表/不存在的key
    redis> EXISTS not_exists
    (integer) 0

    redis> HVALS not_exists
    (empty list or set)
HINCRBY
  • 语法
    HINCRBY key field increment

  • 说明
    为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数,相当于对给定域进行减法操作。如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。如果域 field 不存在,那么在执行命令前,域的值被初始化为 0 。对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误。

  • 返回值
    执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    # increment 为正数

    redis> HEXISTS counter page_view # 对空域进行设置
    (integer) 0

    redis> HINCRBY counter page_view 200
    (integer) 200

    redis> HGET counter page_view
    "200"


    # increment 为负数

    redis> HGET counter page_view
    "200"

    redis> HINCRBY counter page_view -50
    (integer) 150

    redis> HGET counter page_view
    "150"


    # 尝试对字符串值的域执行HINCRBY命令

    redis> HSET myhash string hello,world # 设定一个字符串值
    (integer) 1

    redis> HGET myhash string
    "hello,world"

    redis> HINCRBY myhash string 1 # 命令执行失败,错误。
    (error) ERR hash value is not an integer

    redis> HGET myhash string # 原值不变
    "hello,world"
HINCRBYFLOAT
  • 语法
    HINCRBYFLOAT key field increment

  • 说明
    为哈希表 key 中的域 field 加上浮点数增量 increment 。如果哈希表中没有域 field ,那么 HINCRBYFLOAT 会先将域 field 的值设为 0 ,然后再执行加法操作。如果键 key 不存在,那么 HINCRBYFLOAT 会先创建一个哈希表,再创建域 field ,最后再执行加法操作。
    当以下任意一个条件发生时,返回一个错误:

    • 域 field 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型)
    • 域 field 当前的值或给定的增量 increment 不能解释(parse)为双精度浮点数(double precision floating point number)
  • 返回值
    执行加法操作之后 field 域的值。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    # 值和增量都是普通小数
    redis> HSET mykey field 10.50
    (integer) 1
    redis> HINCRBYFLOAT mykey field 0.1
    "10.6"

    # 值和增量都是指数符号
    redis> HSET mykey field 5.0e3
    (integer) 0
    redis> HINCRBYFLOAT mykey field 2.0e2
    "5200"

    # 对不存在的键执行 HINCRBYFLOAT
    redis> EXISTS price
    (integer) 0
    redis> HINCRBYFLOAT price milk 3.5
    "3.5"
    redis> HGETALL price
    1) "milk"
    2) "3.5"

    # 对不存在的域进行 HINCRBYFLOAT
    redis> HGETALL price
    1) "milk"
    2) "3.5"
    redis> HINCRBYFLOAT price coffee 4.5 # 新增 coffee 域
    "4.5"
    redis> HGETALL price
    1) "milk"
    2) "3.5"
    3) "coffee"
    4) "4.5"
HGETALL
  • 语法
    HGETALL key

  • 说明
    返回哈希表 key 中,所有的域和值。在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。

  • 返回值
    以列表形式返回哈希表的域和域的值。
    若 key 不存在,返回空列表。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    redis> HSET people jack "Jack Sparrow"
    (integer) 1
    redis> HSET people gump "Forrest Gump"
    (integer) 1

    redis> HGETALL people
    1) "jack" # 域
    2) "Jack Sparrow" # 值
    3) "gump"
    4) "Forrest Gump"

列表(list)

特点

  • list是简单的字符串列表,一个key对应多个value
  • 可以添加一个元素到列表的头部(左边)或者尾部(右边)
  • 一个list最多可以包含2^32-1 个元素 (超过42亿)。

常用命令

LPUSH
  • 语法
    LPUSH key value [value …]

  • 说明
    将一个或多个值 value 插入到列表 key 的表头。如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头: 比如说,对空列表 mylist 执行命令 LPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。
    如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。

  • 返回值
    执行 LPUSH 命令后,列表的长度。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # 加入单个元素

    redis> LPUSH languages english
    (integer) 1


    # 加入重复元素
    redis> LPUSH languages english
    (integer) 2

    redis> LRANGE languages 0 -1 # 列表允许重复元素
    1) "english"
    2) "english"


    # 加入多个元素
    redis> LPUSH mylist a b c
    (integer) 3

    redis> LRANGE mylist 0 -1
    1) "c"
    2) "b"
    3) "a"
RPUSH
  • 语法
    RPUSH key value [value …]

  • 说明
    将一个或多个值 value 插入到列表 key 的表尾(最右边)。如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c ,等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。
    如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。

  • 返回值
    执行 RPUSH 操作后,表的长度。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    # 添加单个元素
    redis> RPUSH languages english
    (integer) 1


    # 添加重复元素

    redis> RPUSH languages english
    (integer) 2

    redis> LRANGE languages 0 -1 # 列表允许重复元素
    1) "english"
    2) "english"


    # 添加多个元素

    redis> RPUSH mylist a b c
    (integer) 3

    redis> LRANGE mylist 0 -1
    1) "a"
    2) "b"
    3) "c"
LRANGE
  • 语法
    LRANGE key start stop

  • 说明
    返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
    如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大,那么 LRANGE 返回一个空列表。如果 stop 下标比 end 下标还要大,Redis将 stop 的值设置为 end 。

  • 返回值
    一个列表,包含指定区间内的元素。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    redis> RPUSH fp-language lisp
    (integer) 1

    redis> LRANGE fp-language 0 0
    1) "lisp"

    redis> RPUSH fp-language scheme
    (integer) 2

    redis> LRANGE fp-language 0 1
    1) "lisp"
    2) "scheme"
LPOP
  • 语法
    LPOP key

  • 说明
    移除并返回列表 key 的头元素。

  • 返回值
    列表的头元素。 当 key 不存在时,返回 nil 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    redis> LLEN course
    (integer) 0

    redis> RPUSH course English
    (integer) 1

    redis> RPUSH course Mathematics
    (integer) 2

    redis> LPOP course # 移除头元素
    "English"
RPOP
  • 语法
    RPOP key

  • 说明
    移除并返回列表 key 的尾元素。

  • 返回值
    列表的尾元素。 当 key 不存在时,返回 nil 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    redis> LLEN course
    (integer) 0

    redis> RPUSH course English
    (integer) 1

    redis> RPUSH course Mathematics
    (integer) 2

    redis> LPOP course # 移除尾元素
    "Mathematics"
LINDEX
  • 语法
    LINDEX key index

  • 说明
    返回列表 key 中,下标为 index 的元素。下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
    如果 key 不是列表类型,返回一个错误。

  • 返回值
    列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内(out of range),返回 nil 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    redis> LPUSH mylist "World"
    (integer) 1

    redis> LPUSH mylist "Hello"
    (integer) 2

    redis> LINDEX mylist 0
    "Hello"

    redis> LINDEX mylist -1
    "World"

    redis> LINDEX mylist 3 # index不在 mylist 的区间范围内
    (nil)
LLEN
  • 语法
    LLEN key

  • 说明
    返回列表 key 的长度。

  • 返回值
    列表的尾元素。 当 key 不存在时,返回 nil 。如果 key 不存在,则 key 被解释为一个空列表,返回 0 。如果 key 不是列表类型,返回一个错误。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 空列表
    redis> LLEN job
    (integer) 0

    # 非空列表
    redis> LPUSH job "cook food"
    (integer) 1
    redis> LPUSH job "have lunch"
    (integer) 2
    redis> LLEN job
    (integer) 2
LREM
  • 语法
    LREM key count value

  • 说明
    根据参数 count 的值,移除列表中与参数 value 相等的元素。
    count 的值可以是以下几种:

    • count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
    • count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
    • count = 0 : 移除表中所有与 value 相等的值。
  • 返回值
    被移除元素的数量。 因为不存在的 key 被视作空表(empty list),所以当 key 不存在时, LREM 命令总是返回 0 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    # 先创建一个表,内容排列是
    # morning hello morning helllo morning

    redis> LPUSH greet "morning"
    (integer) 1
    redis> LPUSH greet "hello"
    (integer) 2
    redis> LPUSH greet "morning"
    (integer) 3
    redis> LPUSH greet "hello"
    (integer) 4
    redis> LPUSH greet "morning"
    (integer) 5

    redis> LRANGE greet 0 4 # 查看所有元素
    1) "morning"
    2) "hello"
    3) "morning"
    4) "hello"
    5) "morning"

    redis> LREM greet 2 morning # 移除从表头到表尾,最先发现的两个 morning
    (integer) 2 # 两个元素被移除

    redis> LLEN greet # 还剩 3 个元素
    (integer) 3

    redis> LRANGE greet 0 2
    1) "hello"
    2) "hello"
    3) "morning"

    redis> LREM greet -1 morning # 移除从表尾到表头,第一个 morning
    (integer) 1

    redis> LLEN greet # 剩下两个元素
    (integer) 2

    redis> LRANGE greet 0 1
    1) "hello"
    2) "hello"

    redis> LREM greet 0 hello # 移除表中所有 hello
    (integer) 2 # 两个 hello 被移除

    redis> LLEN greet
    (integer) 0
LTRIM
  • 语法
    LTRIM key start stop

  • 说明
    对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。
    下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
    当 key 不是列表类型时,返回一个错误。
    如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大,或者 start > stop , LTRIM 返回一个空列表(因为 LTRIM 已经将整个列表清空)。如果 stop 下标比 end 下标还要大,Redis将 stop 的值设置为 end 。

  • 返回值
    命令执行成功时,返回 ok 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    # 情况 1: 常见情况, start 和 stop 都在列表的索引范围之内
    redis> LRANGE alpha 0 -1 # alpha 是一个包含 5 个字符串的列表
    1) "h"
    2) "e"
    3) "l"
    4) "l"
    5) "o"
    redis> LTRIM alpha 1 -1 # 删除 alpha 列表索引为 0 的元素
    OK
    redis> LRANGE alpha 0 -1 # "h" 被删除了
    1) "e"
    2) "l"
    3) "l"
    4) "o"

    # 情况 2: stop 比列表的最大下标还要大
    redis> LTRIM alpha 1 10086 # 保留 alpha 列表索引 1 至索引 10086 上的元素
    OK
    redis> LRANGE alpha 0 -1 # 只有索引 0 上的元素 "e" 被删除了,其他元素还在
    1) "l"
    2) "l"
    3) "o"

    # 情况 3: start 和 stop 都比列表的最大下标要大,并且 start < stop
    redis> LTRIM alpha 10086 123321
    OK
    redis> LRANGE alpha 0 -1 # 列表被清空
    (empty list or set)

    # 情况 4: start 和 stop 都比列表的最大下标要大,并且 start > stop
    redis> RPUSH new-alpha "h" "e" "l" "l" "o" # 重新建立一个新列表
    (integer) 5
    redis> LRANGE new-alpha 0 -1
    1) "h"
    2) "e"
    3) "l"
    4) "l"
    5) "o"
    redis> LTRIM new-alpha 123321 10086 # 执行 LTRIM
    OK
    redis> LRANGE new-alpha 0 -1 # 同样被清空
    (empty list or set)
RPOPLPUSH
  • 语法
    RPOPLPUSH source destination
  • 说明
    命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:
    • 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
    • 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。

如果 source 不存在,值 nil 被返回,并且不执行其他动作。如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作。

  • 返回值
    被弹出的元素。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    	# source 和 destination 不同
    redis> LRANGE alpha 0 -1 # 查看所有元素
    1) "a"
    2) "b"
    3) "c"
    4) "d"
    redis> RPOPLPUSH alpha reciver # 执行一次 RPOPLPUSH 看看
    "d"
    redis> LRANGE alpha 0 -1
    1) "a"
    2) "b"
    3) "c"
    redis> LRANGE reciver 0 -1
    1) "d"
    redis> RPOPLPUSH alpha reciver # 再执行一次,证实 RPOP 和 LPUSH 的位置正确
    "c"
    redis> LRANGE alpha 0 -1
    1) "a"
    2) "b"
    redis> LRANGE reciver 0 -1
    1) "c"
    2) "d"

    # source 和 destination 相同
    redis> LRANGE number 0 -1
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    redis> RPOPLPUSH number number
    "4"
    redis> LRANGE number 0 -1 # 4 被旋转到了表头
    1) "4"
    2) "1"
    3) "2"
    4) "3"
    redis> RPOPLPUSH number number
    "3"
    redis> LRANGE number 0 -1 # 这次是 3 被旋转到了表头
    1) "3"
    2) "4"
    3) "1"
    4) "2"
BRPOPLPUSH
  • 语法
    BRPOPLPUSH source destination timeout

  • 说明
    BRPOPLPUSH 是 RPOPLPUSH source destination 的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH 的表现和 RPOPLPUSH source destination 一样。
    当列表 source 为空时, BRPOPLPUSH 命令将阻塞连接,直到等待超时,或有另一个客户端对 source 执行 LPUSH key value [value …] 或 RPUSH key value [value …] 命令为止。
    超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) 。

  • 返回值
    假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 非空列表
    redis> BRPOPLPUSH msg reciver 500
    "hello moto" # 弹出元素的值
    (3.38s) # 等待时长
    redis> LLEN reciver
    (integer) 1
    redis> LRANGE reciver 0 0
    1) "hello moto"

    # 空列表
    redis> BRPOPLPUSH msg reciver 1
    (nil)
    (1.34s)
LSET
  • 语法
    LSET key index value

  • 说明
    将列表 key 下标为 index 的元素的值设置为 value 。
    当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。

  • 返回值
    操作成功返回 ok ,否则返回错误信息。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 对空列表(key 不存在)进行 LSET
    redis> EXISTS list
    (integer) 0
    redis> LSET list 0 item
    (error) ERR no such key

    # 对非空列表进行 LSET
    redis> LPUSH job "cook food"
    (integer) 1
    redis> LRANGE job 0 0
    1) "cook food"
    redis> LSET job 0 "play game"
    OK
    redis> LRANGE job 0 0
    1) "play game"

    # index 超出范围
    redis> LLEN list # 列表长度为 1
    (integer) 1
    redis> LSET list 3 'out of range'
    (error) ERR index out of range

集合(set)

特点

  • set是无序不能重复的集合,单值多value
  • set是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
  • 集合中最大的成员数为 2^32 - 1 (超过42亿个成员)

常用命令

SADD
  • 语法
    SADD key member [member …]

  • 说明
    将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
    假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
    当 key 不是集合类型时,返回一个错误。

  • 返回值
    被添加到集合中的新元素的数量,不包括被忽略的元素。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 添加单个元素
    redis> SADD bbs "discuz.net"
    (integer) 1

    # 添加重复元素
    redis> SADD bbs "discuz.net"
    (integer) 0

    # 添加多个元素
    redis> SADD bbs "tianya.cn" "groups.google.com"
    (integer) 2
    redis> SMEMBERS bbs
    1) "discuz.net"
    2) "groups.google.com"
    3) "tianya.cn"
SMEMBERS
  • 语法
    SMEMBERS key

  • 说明
    返回集合 key 中的所有成员。不存在的 key 被视为空集合。

  • 返回值
    集合中的所有成员。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # key 不存在或集合为空
    redis> EXISTS not_exists_key
    (integer) 0
    redis> SMEMBERS not_exists_key
    (empty list or set)

    # 非空集合
    redis> SADD language Ruby Python Clojure
    (integer) 3
    redis> SMEMBERS language
    1) "Python"
    2) "Ruby"
    3) "Clojure"
SISMEMBER
  • 语法
    SISMEMBER key member

  • 说明
    判断 member 元素是否集合 key 的成员。

  • 返回值
    如果 member 元素是集合的成员,返回 1 。 如果 member 元素不是集合的成员,或 key 不存在,返回 0 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    redis> SMEMBERS website
    1) "baidu.com"
    2) "google.cn"
    3) "souhu.com"

    redis> SISMEMBER website "tencent.com"
    (integer) 0

    redis> SISMEMBER website "baidu.com"
    (integer) 1
SCARD
  • 语法
    SCARD key

  • 说明
    返回集合 key 的基数(集合中元素的数量)。

  • 返回值
    集合的基数。 当 key 不存在时,返回 0 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    redis> SADD tool pc printer phone
    (integer) 3

    redis> SCARD tool # 非空集合
    (integer) 3

    redis> DEL tool
    (integer) 1

    redis> SCARD tool # 空集合
    (integer) 0
SREM
  • 语法
    SREM key member [member …]

  • 说明
    移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。当 key 不是集合类型,返回一个错误。

  • 返回值
    被成功移除的元素的数量,不包括被忽略的元素。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 测试数据
    redis> SMEMBERS languages
    1) "c"
    2) "lisp"
    3) "python"
    4) "ruby"

    # 移除单个元素
    redis> SREM languages ruby
    (integer) 1

    # 移除不存在元素
    redis> SREM languages non-exists-language
    (integer) 0

    # 移除多个元素
    redis> SREM languages lisp python c
    (integer) 3
    redis> SMEMBERS languages
    (empty list or set)
SRANDMEMBER
  • 语法
    SRANDMEMBER key [count]

  • 说明
    如果命令执行时,只提供了 key 参数,那么返回集合中的一个随机元素。
    从 Redis 2.6 版本开始, SRANDMEMBER 命令接受可选的 count 参数:

    • 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。
    • 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。

    该操作和 SPOP key 相似,但 SPOP key 将随机元素从集合中移除并返回,而 SRANDMEMBER 则仅仅返回随机元素,而不对集合进行任何改动。

  • 返回值
    只提供 key 参数时,返回一个元素;如果集合为空,返回 nil 。 如果提供了 count 参数,那么返回一个数组;如果集合为空,返回空数组。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    # 添加元素
    redis> SADD fruit apple banana cherry
    (integer) 3

    # 只给定 key 参数,返回一个随机元素
    redis> SRANDMEMBER fruit
    "cherry"
    redis> SRANDMEMBER fruit
    "apple"

    # 给定 3 为 count 参数,返回 3 个随机元素
    # 每个随机元素都不相同
    redis> SRANDMEMBER fruit 3
    1) "apple"
    2) "banana"
    3) "cherry"

    # 给定 -3 为 count 参数,返回 3 个随机元素
    # 元素可能会重复出现多次
    redis> SRANDMEMBER fruit -3
    1) "banana"
    2) "cherry"
    3) "apple"
    redis> SRANDMEMBER fruit -3
    1) "apple"
    2) "apple"
    3) "cherry"

    # 如果 count 是整数,且大于等于集合基数,那么返回整个集合
    redis> SRANDMEMBER fruit 10
    1) "apple"
    2) "banana"
    3) "cherry"

    # 如果 count 是负数,且 count 的绝对值大于集合的基数
    # 那么返回的数组的长度为 count 的绝对值
    redis> SRANDMEMBER fruit -10
    1) "banana"
    2) "apple"
    3) "banana"
    4) "cherry"
    5) "apple"
    6) "apple"
    7) "cherry"
    8) "apple"
    9) "apple"
    10) "banana"

    # SRANDMEMBER 并不会修改集合内容
    redis> SMEMBERS fruit
    1) "apple"
    2) "cherry"
    3) "banana"

    # 集合为空时返回 nil 或者空数组
    redis> SRANDMEMBER not-exists
    (nil)
    redis> SRANDMEMBER not-eixsts 10
    (empty list or set)
SPOP
  • 语法
    SPOP key

  • 说明
    移除并返回集合中的一个随机元素。如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 SRANDMEMBER key [count] 命令。

  • 返回值
    被移除的随机元素。 当 key 不存在或 key 是空集时,返回 nil 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    redis> SMEMBERS db
    1) "MySQL"
    2) "MongoDB"
    3) "Redis"

    redis> SPOP db
    "Redis"

    redis> SMEMBERS db
    1) "MySQL"
    2) "MongoDB"

    redis> SPOP db
    "MySQL"

    redis> SMEMBERS db
    1) "MongoDB"
SMOVE
  • 语法
    SMOVE source destination member

  • 说明
    将 member 元素从 source 集合移动到 destination 集合。SMOVE 是原子性操作。
    如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回 0 。否则, member 元素从 source 集合中被移除,并添加到 destination 集合中去。
    当 destination 集合已经包含 member 元素时, SMOVE 命令只是简单地将 source 集合中的 member 元素删除。
    当 source 或 destination 不是集合类型时,返回一个错误。

  • 返回值
    如果 member 元素被成功移除,返回 1 。 如果 member 元素不是 source 集合的成员,并且没有任何操作对 destination 集合执行,那么返回 0 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    redis> SMEMBERS songs
    1) "Billie Jean"
    2) "Believe Me"

    redis> SMEMBERS my_songs
    (empty list or set)

    redis> SMOVE songs my_songs "Believe Me"
    (integer) 1

    redis> SMEMBERS songs
    1) "Billie Jean"

    redis> SMEMBERS my_songs
    1) "Believe Me"
SDIFF
  • 语法
    SDIFF key [key …]

  • 说明
    返回一个集合的全部成员,该集合是所有给定集合之间的差集。不存在的 key 被视为空集。

  • 返回值
    一个包含差集成员的列表。。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    redis> SMEMBERS peter's_movies
    1) "bet man"
    2) "start war"
    3) "2012"

    redis> SMEMBERS joe's_movies
    1) "hi, lady"
    2) "Fast Five"
    3) "2012"

    redis> SDIFF peter's_movies joe's_movies
    1) "bet man"
    2) "start war"
SUNION
  • 语法
    SUNION key [key …]

  • 说明
    返回一个集合的全部成员,该集合是所有给定集合的并集。不存在的 key 被视为空集。

  • 返回值
    并集成员的列表。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    redis> SMEMBERS songs
    1) "Billie Jean"

    redis> SMEMBERS my_songs
    1) "Believe Me"

    redis> SUNION songs my_songs
    1) "Billie Jean"
    2) "Believe Me"

有序集合(zset)

特点

  • zset是有序不可重复的集合
  • zset每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序
  • zset的成员是唯一的,但分数(score)却可以重复
  • zset通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
  • zset中最大的成员数为 2^32 - 1 (超过42亿个成员)

常用命令

ZADD
  • 语法
    ZADD key score member [[score member] [score member] …]

  • 说明
    将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
    如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。
    score 值可以是整数值或双精度浮点数。
    如果 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
    当 key 存在但不是有序集类型时,返回一个错误。

  • 返回值
    被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    # 添加单个元素
    redis> ZADD page_rank 10 google.com
    (integer) 1

    # 添加多个元素
    redis> ZADD page_rank 9 baidu.com 8 bing.com
    (integer) 2
    redis> ZRANGE page_rank 0 -1 WITHSCORES
    1) "bing.com"
    2) "8"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"

    # 添加已存在元素,且 score 值不变
    redis> ZADD page_rank 10 google.com
    (integer) 0
    redis> ZRANGE page_rank 0 -1 WITHSCORES # 没有改变
    1) "bing.com"
    2) "8"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"

    # 添加已存在元素,但是改变 score 值
    redis> ZADD page_rank 6 bing.com
    (integer) 0
    redis> ZRANGE page_rank 0 -1 WITHSCORES # bing.com 元素的 score 值被改变
    1) "bing.com"
    2) "6"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"
ZRANGE
  • 语法
    ZRANGE key start stop [WITHSCORES]

  • 说明
    返回有序集 key 中,指定区间内的成员。
    其中成员的位置按 score 值递增(从小到大)来排序。
    具有相同 score 值的成员按字典序(lexicographical order )来排列。
    如果你需要成员按 score 值递减(从大到小)来排列,请使用 ZREVRANGE key start stop [WITHSCORES] 命令。
    下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。 你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
    超出范围的下标并不会引起错误。 比如说,当 start 的值比有序集的最大下标还要大,或是 start > stop 时, ZRANGE 命令只是简单地返回一个空列表。 另一方面,假如 stop 参数的值比有序集的最大下标还要大,那么 Redis 将 stop 当作最大下标来处理。
    可以通过使用 WITHSCORES 选项,来让成员和它的 score 值一并返回,返回列表以 value1,score1, …, valueN,scoreN 的格式表示。 客户端库可能会返回一些更复杂的数据类型,比如数组、元组等。

  • 返回值
    指定区间内,带有 score 值(可选)的有序集成员的列表。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    redis > ZRANGE salary 0 -1 WITHSCORES    # 显示整个有序集成员
    1) "jack"
    2) "3500"
    3) "tom"
    4) "5000"
    5) "boss"
    6) "10086"

    redis > ZRANGE salary 1 2 WITHSCORES # 显示有序集下标区间 12 的成员
    1) "tom"
    2) "5000"
    3) "boss"
    4) "10086"

    redis > ZRANGE salary 0 200000 WITHSCORES # 测试 end 下标超出最大下标时的情况
    1) "jack"
    2) "3500"
    3) "tom"
    4) "5000"
    5) "boss"
    6) "10086"

    redis > ZRANGE salary 200000 3000000 WITHSCORES # 测试当给定区间不存在于有序集时的情况
    (empty list or set)
ZSCORE
  • 语法
    ZSCORE key member

  • 说明
    返回有序集 key 中,成员 member 的 score 值。如果 member 元素不是有序集 key 的成员,或 key 不存在,返回 nil 。

  • 返回值
    member 成员的 score 值,以字符串形式表示。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    redis> ZRANGE salary 0 -1 WITHSCORES    # 测试数据
    1) "tom"
    2) "2000"
    3) "peter"
    4) "3500"
    5) "jack"
    6) "5000"

    redis> ZSCORE salary peter # 注意返回值是字符串
    "3500"
ZCARD
  • 语法
    ZCARD key

  • 说明
    返回有序集 key 的数量。

  • 返回值
    当 key 存在且是有序集类型时,返回有序集的数量。 当 key 不存在时,返回 0 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    redis > ZADD salary 2000 tom    # 添加一个成员
    (integer) 1

    redis > ZCARD salary
    (integer) 1

    redis > ZADD salary 5000 jack # 再添加一个成员
    (integer) 1

    redis > ZCARD salary
    (integer) 2

    redis > EXISTS non_exists_key # 对不存在的 key 进行 ZCARD 操作
    (integer) 0

    redis > ZCARD non_exists_key
    (integer) 0
ZCOUNT
  • 语法
    ZCOUNT key min max

  • 说明
    返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。

  • 返回值
    score 值在 min 和 max 之间的成员的数量。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    redis> ZRANGE salary 0 -1 WITHSCORES  # 测试数据
    1) "jack"
    2) "2000"
    3) "peter"
    4) "3500"
    5) "tom"
    6) "5000"

    redis> ZCOUNT salary 2000 5000 # 计算薪水在 2000-5000 之间的人数
    (integer) 3

    redis> ZCOUNT salary 3000 5000 # 计算薪水在 3000-5000 之间的人数
    (integer) 2
ZRANK
  • 语法
    ZRANK key member

  • 说明
    返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。
    排名以 0 为底,也就是说, score 值最小的成员排名为 0 。
    使用 ZREVRANK key member 命令可以获得成员按 score 值递减(从大到小)排列的排名。

  • 返回值
    如果 member 是有序集 key 的成员,返回 member 的排名。 如果 member 不是有序集 key 的成员,返回 nil 。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    redis> ZRANGE salary 0 -1 WITHSCORES  # 显示所有成员及其score值
    1) "peter"
    2) "3500"
    3) "tom"
    4) "4000"
    5) "jack"
    6) "5000"

    redis> ZRANK salary tom # 显示 tom 的薪水排名,第二
    (integer) 1
ZREM
  • 语法
    ZREM key member [member …]

  • 说明
    移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。当 key 存在但不是有序集类型时,返回一个错误。

  • 返回值
    被成功移除的成员的数量,不包括被忽略的成员。

  • 相关案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    # 测试数据
    redis> ZRANGE page_rank 0 -1 WITHSCORES
    1) "bing.com"
    2) "8"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"

    # 移除单个元素
    redis> ZREM page_rank google.com
    (integer) 1
    redis> ZRANGE page_rank 0 -1 WITHSCORES
    1) "bing.com"
    2) "8"
    3) "baidu.com"
    4) "9"

    # 移除多个元素
    redis> ZREM page_rank baidu.com bing.com
    (integer) 2
    redis> ZRANGE page_rank 0 -1 WITHSCORES
    (empty list or set)

    # 移除不存在元素
    redis> ZREM page_rank non-exists-element
    (integer) 0

持久化

RDB(Redis DataBase)

是什么

  • 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
  • rdb 保存的是dump.rdb文件
  • 相关配置在配置文件中搜索### SNAPSHOTTING ###

如何触发RDB快照

  • 配置文件中默认的快照配置dbfilename dump.rdb
    • 冷拷贝后重新使用
    • 可以cp dump.rdb dump_new.rdb
  • 命令save或者是bgsave
    • Save:save时只管保存其它不管,命令执行完前,其它命令处于等待状态,数据量大时会出现阻塞
    • BGSAVE:Redis会在后台异步进行快照操作, 快照同时还可以响应客户端请求。可以通过lastsave 命令获取最后一次成功执行快照的时间。基本不会阻塞进程
  • 执行flushall命令,也会产生dump.rdb文件,但里面是空的,无意义

如何恢复

  • 将备份文件 (dump.rdb) 移动到 Redis 安装目录并启动服务即可
  • CONFIG GET dir获取目录

自动生成RDB的策略

配置 seconds changes
save 900 1
save 300 10
save 60 1000

数据写入量不受控制,所以生成的规则也不好控制。频繁的操作会对硬盘造成一定压力。

优势与劣势

  • 优势
    • 体积更小
      相同的数据量rdb数据比aof的小,因为rdb是紧凑型文件
    • 恢复更快
      因为rdb是数据的快照,基本上就是数据的复制,不用重新读取再写入内存
    • 性能更高
      父进程在保存rdb时候只需要fork一个子进程,无需父进程的进行其他io操作,也保证了服务器的性能
  • 劣势
    • 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改,根据自己的配置,最少五分钟,甚至几小时的数据。

参考链接

AOF(Append Only File)

是什么

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换言之,Redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

AOF配置

  • 相关配置在配置文件的位置 - 在redis.conf搜寻### APPEND ONLY MODE ###
  • AOF保存的是appendonly.aof文件(在配置文件可修改文件名)

AOF启动/修复/恢复

  • 正常恢复
    • 启动:设置Yes
      • 修改默认的appendonly no,改为yes
    • 将有数据的aof文件复制一份保存到对应目录(config get dir)
    • 恢复:重启redis然后重新加载
  • 异常恢复
    • 启动:设置Yes
      • 修改默认的appendonly no,改为yes
  • 备份被写坏的AOF文件
  • 修复:
    • Redis-check-aof --fix进行修复
  • 恢复:重启redis然后重新加载

rewrite

  • 是什么
    AOF采用文件追加方式,文件会越来越大。为避免出现此种情况,新增了重写机制, 当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩, 只保留可以恢复数据的最小指令集。可以使用命令bgrewriteaof
  • 重写原理
    AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename), 遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件, 而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
  • 触发机制
    Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

三种策略对比

命令 优点 缺点
always (每修改同步) 每次发生数据变更会被立即记录到磁盘,数据完整性比较好 IO开销大,性能差
everysec (没秒同步) 每秒记录 如果一秒内宕机,有数据丢失 可能会丢一秒数据
no 从不同步 不可控

一般使用默认配置everysec

优势与劣势

  • 优势
    • 数据完整性好
      可以设置fsync策略,一般默认是everysec,也可以设置每次写入追加,所以即使服务死掉了,最多丢失一秒数据
  • 劣势
    • 体积大
      相同数据集的数据而言aof文件要远大于rdb文件
    • 恢复速度慢
      要重新执行一遍大体积日志文件
    • 性能相对较差

参考链接

事务

是什么

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。Redis对事物是部分支持(参考冤头债主)且不支持回滚。

能干嘛

一个队列中,一次性、顺序性、排他性的执行一系列命令。

常用命令

命令 描述
DISCARD 取消事务,放弃执行事务块内的所有命令。
EXEC 执行所有事务块内的命令。
MULTI 标记一个事务块的开始。
UNWATCH 取消 WATCH 命令对所有 key 的监视。
WATCH key [key …] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

case场景

  • 放弃事务
    使用DISCARD 命令
  • 全体连坐
    输入语句命令过程中有报错,之后执行事务所有语句都不会执行。相当于java的编译异常。
  • 冤头债主
    输入语句命令过程中会入队,执行事务的时候只有有问题的语句报错其他语句正常执行。比如incr k1(k1不是数字类型)。相当于Java运行异常。

watch与unwatch

Redis事务处理

watch

  • watch命令监控了key,如果key被修改了,后面一个事务的执行失效
  • watch指令,类似乐观锁(行加版本号),事务提交时,如果Key的值已被别的客户端改变, 比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行

unwatch

  • 取消 WATCH 命令对所有 key 的监视。
    如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。因为 EXEC 命令会执行事务,因此 WATCH 命令的效果已经产生了;而 DISCARD 命令在取消事务的同时也会取消所有对 key 的监视,因此这两个命令执行之后,就没有必要执行 UNWATCH 了。

3阶段

  • 开启
    以MULTI开始一个事务
  • 入队
    将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
  • 执行
    由EXEC命令触发事务

3特性

  • 单独的隔离操作
    事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 没有隔离级别的概念
    队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行, 也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题
  • 不保证原子性
    Redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。所以Redis对事物是部分支持(参考冤头债主)的。

发布订阅

  • 企业一般不会用这个做消息中间件,会选择ActiveMQ之类的
  • Redis本身不提供消息队列,而是通过列表实现。
  • 消息队列与发布订阅的区别
    消息队列中的资源只用一个客户端获得。而发布订阅消息是所有订阅者均能获得
  • 相关命令
    SUBSCRIBE 、PUBLISH

主从复制

是什么

主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。

能干嘛

  • 读写分离
  • 容灾恢复

准备工作

  • 配从(库)不配主(库)
  • 从库配置命令:slaveof 主库IP 主库端口
    • 每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件(具体位置:redis.conf搜寻#### REPLICATION ####)
    • info replication
  • 修改配置文件细节操作
    • 拷贝多个redis.conf文件,按’redis[port].conf’重命名
    • 开启daemonize yes
    • pid文件名字
    • 指定端口
    • log文件名字
    • dump.rdb名字

案例演示

一主二仆

一个Master两个Slave,即79主机是80和81主机的master 。

相关问题
  • slave1、slave2是从头开始复制还是从切入点开始复制?比如从k4进来,那之前的123是否也可以复制?
    答:从头开始复制;123也可以复制
  • 从机是否可以写?set可否?
    答:从机不可写,不可set,主机可写
  • 主机shutdown后情况如何?从机是上位还是原地待命
    答:从机还是原地待命(咸鱼翻身,还是咸鱼)
  • 主机又回来了后,主机新增记录,从机还能否顺利复制?
    答:能
  • 其中一台从机down后情况如何?依照原有它能跟上大部队吗?
    答:不能跟上,每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件(具体位置:redis.conf搜寻#### REPLICATION ####)

薪火相传

目的是去中心化,79主机是80主机的master且 80主机是81主机的master,最终80主机在Redis中还是slave。本质也是一主二仆

反客为主

从机执行SLAVEOF no one命令成为master,需要成为该从机的从机执行slaveof ip 端口命令。目的是使当前数据库停止与其他数据库的同步,转成主数据库,形成新的中心点。

事实上以上三种案例在实际生产环境中不使用(不可能半夜出问题了还人工去执行Redis命令),实际中应该是自动反客为主模式,即下面讲的哨兵模式。

哨兵模式(sentinel)

是什么

一组sentinel能同时监控多个master。反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。

配置步骤

  • 调整结构,6379带着6380、6381
  • 新建sentinel.conf文件,名字绝不能错
  • 配置哨兵,填写内容
    • sentinel monitor 被监控数据库名字(自己起名字) 127.0.0.1 6379 1
    • 上面最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机(PS. 跟官网的描述有出入,下面有官方文档说明)
  • 启动哨兵
    • redis-sentinel /sentinel.conf(上述目录依照各自的实际情况配置,可能目录不同)
  • 正常主从演示
  • 原有的master挂了
  • 投票新选
  • 重新主从继续开工,info replication查查看

问题

如果之前挂了的master重启回来,会不会双master冲突?
答: 不会,原master会变成slave。

复制的原理

  • slave启动成功连接到master后会发送一个sync命令
  • master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令, 在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步
  • 全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
  • 增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
  • 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行

复制的缺点

由于所有的写操作都是先在Master上操作,然后同步更新到slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

集群

为什么要用集群

  • 并发量
  • 数据量

数据分布

  • 顺序分区
    顺序分布其实不支持批量操作
  • 哈希分区
    节点取余: 建议多倍扩容比较好,数据迁移量少
    一致性哈希:token环,只影响邻近节点,对其他节点影响小(节点多时候建议)
  • 虚拟槽分区

温馨提示:本文是观看尚硅谷周阳老师的Redis教学视频后写的学习笔记,如有错误请联系修改。

自愿打赏成功后发送截图到邮箱1271826574@qq.com可获取本文的MarkDown源文件,邮件标题为:需要一份study_of_redis。