文章目录

  • 1、预备知识
  • 1.1:一些全局命令
  • 2:数据结构和内部编码
  • 2.1:字符串
  • 2.1.1:常用命令
  • 2.1.2:不常用命令
  • 2.2: 内部编码
  • 2.3: 使用场景
  • 3:哈希
  • 3.1:命令
  • 3.2:内部编码
  • 3.3:使用场景


1、预备知识

   在正式介绍5种数据结构之前,了解一下Redis的一些全局命令、数据结构和内部编码、单线程命令处理机制是十分有必要的,它们能为后面内容的学习打下一个好的基础,主要体现在两个方面:第一、Redis的命令有上百个,如果纯靠死记硬背比较困难,但是如果理解Redis的一些机制,会发现这些命令有很强的通用性。第二、Redis不是万金油,有些数据结构和命令必须在特定场景下使用,一旦使用不当可能对Redis本身或者应用本身造成致命伤害。

1.1:一些全局命令

   Redis有5种数据结构,它们是键值对中的值,对于键来说有一些通用的 命令。

1.查看所有键:keys * .

redissonClient操作APi redis常用api_redissonClient操作APi


2. 键总数:dbsize

   dbsize命令在计算键总数时不会遍历所有键,而是直接获取Redis内置的 键总数变量,所以dbsize命令的时间复杂度是O(1)。而keys命令会遍历所 有键,所以它的时间复杂度是O(n),当Redis保存了大量键时,线上环境禁止使用。

3. 检查键是否存在:exists key

   如果键存在则返回1,不存在则返回0:

4. 删除键:del key [key …]

   del是一个通用命令,无论值是什么数据结构类型,del命令都可以将其 删除,例如下面将字符串类型的键java和列表类型的键mylist分别删除。

5. 键过期:expire key seconds

   Redis支持对键添加过期时间,当超过过期时间后,会自动删除键,例 如为键hello设置了3秒过期时间:

redissonClient操作APi redis常用api_redissonClient操作APi_02


ttl命令会返回键的剩余过期时间,它有3种返回值:

  • 大于等于0的整数:键剩余的过期时间。
  • -1键没设置过期时间。
  • -2键不存在

6.键的数据结构类型:type key

   例如键hello是字符串类型,返回结果为string。键mylist是列表类型,返 回结果为list:

redissonClient操作APi redis常用api_缓存_03

2:数据结构和内部编码

   type命令实际返回的就是当前键的数据结构类型,它们分别是: string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集 合),但这些只是Redis对外的数据结构,如图:

redissonClient操作APi redis常用api_redis_04


  实际上每种数据结构都有自己底层的内部编码实现,而且是多种实现, 这样Redis会在合适的场景选择合适的内部编码,如图2-2所示。

redissonClient操作APi redis常用api_数据库_05


可以通过object encoding命查询 内部编码:

redissonClient操作APi redis常用api_redis_06

Redis这样设计的好处:  
  第一,可以改进内部编码,而对外的数据 结构和命令没有影响,这样一旦开发出更优秀的内部编码,无需改动外部数据结构和命令,例如Redis3.2提供了quicklist,结合了ziplist和linkedlist两者的优势,为列表类型提供了一种更为优秀的内部编码实现,而对外部用户来说基本感知不到。
  第二,多种内部编码实现可以在不同场景下发挥各自的优 势,例如ziplist比较节省内存,但是在列表元素比较多的情况下,性能会有 所下降,这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist。

2.1:字符串

  字符串类型是Redis最基础的数据结构。首先键都是字符串类型,而且 其他几种数据结构都是在字符串类型基础上构建的,所以字符串类型能为其 他四种数据结构的学习奠定基础。如图2-7所示,字符串类型的值实际可以 是字符串(简单的字符串、复杂的字符串(例如JSON、XML))、数字 (整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能 超过512MB。

redissonClient操作APi redis常用api_缓存_07

2.1.1:常用命令


1.设置值

set key value [ex seconds] [px milliseconds] [nx|xx]

set命令有几个选项:

  • ex seconds:为键设置秒级过期时间。
  • px milliseconds:为键设置毫秒级过期时间。
  • nx:键必须不存在,才可以设置成功,用于添加。
  • xx:与nx相反,键必须存在,才可以设置成功,用于更新。

除了set选项,Redis还提供了setex和setnx两个命令:

setex key seconds value 
 setnx key value

setnx和setxx在实际使用中有什么应用场景吗?以setnx命令为例子,由于 Redis的单线程命令处理机制,如果有多个客户端同时执行setnx key value, 根据setnx的特性只有一个客户端能设置成功,setnx可以作为分布式锁的一种 实现方案


2.获取值:get key 如果要获取的键不存在,则返回nil(空)


3.批量设置值

mset key value [key value ...]

4.批量获取值

mget key value [key value ...]

如果有些键不存在,那么它的值为nil(空),结果是按照传入键的顺序返回:

redissonClient操作APi redis常用api_数据库_08


批量操作命令可以有效提高开发效率,假如没有mget这样的命令,要执行n次get命令需要按照图2-8的方式来执行,具体耗时如下:

n次get时间 = n次网络时间 + n次命令时间

redissonClient操作APi redis常用api_Redis_09


使用mget命令后,要执行n次get命令操作只需要按照图2-9的方式来完成,具体耗时如下:

n次get时间 = 1次网络时间 + n次命令时间

redissonClient操作APi redis常用api_数据库_10

  对于Redis客户端来说,一次命令除了命令时间还是有网络时间,而Redis的处理能力已经足够高,所以对于开发人员来说,网络可能会成为性能的瓶颈,所以学会使用批量操作,有助于提高业务处理效率,当不能无节制,不然会造成Redis阻塞或网络阻塞。

redissonClient操作APi redis常用api_Redis_11


5.计数:incr key

  incr命令用于对值做自增操作,返回结果分为三种情况:

  • 值不是整数,返回错误。
  • 值是整数,返回自增后的结果。
  • 键不存在,按照值为0自增,返回结果为1。
    除了incr命令,Redis提供了decr(自减)、incrby(自增指定数字)、 decrby(自减指定数字)、incrbyfloat(自增浮点数):
decr key 
incrby key increment 
decrby key decrement 
incrbyfloat key increment

  很多存储系统和编程语言内部使用CAS机制实现计数功能,会有一定的 CPU开销,但在Redis中完全不存在这个问题,因为Redis是单线程架构,任 何命令到了Redis服务端都要顺序执行。

2.1.2:不常用命令


1.追加值:append key value

redissonClient操作APi redis常用api_redissonClient操作APi_12


2.字符串长度:strlen key
每个中文占用3个字节


3:设置并返回原值:getset key value

redissonClient操作APi redis常用api_数据库_13


4.设置指定位置的字符:setrange key offeset value

下面操作将值由jedis变为了redis:

redissonClient操作APi redis常用api_Redis_14


5.获取部分字符串:getrange key start end

偏移量从0开始计算

redissonClient操作APi redis常用api_缓存_15

2.2: 内部编码

字符串类型的内部编码有3种:

  • nt:8个字节的长整型。
  • embstr:小于等于39个字节的字符串。
  • raw:大于39个字节的字符串。

Redis会根据当前值的类型和长度决定使用哪种内部编码实现。

整数类型示例如下:

redissonClient操作APi redis常用api_缓存_16


短字符串示例如下:

redissonClient操作APi redis常用api_redis_17


长字符串示例如下:

redissonClient操作APi redis常用api_数据库_18

2.3: 使用场景

1.缓存功能

  图2-10是比较典型的缓存使用场景,其中Redis作为缓存层,MySQL作 为存储层,绝大部分请求的数据都是从Redis中获取。由于Redis具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用。

redissonClient操作APi redis常用api_redissonClient操作APi_19


2.计数

  许多应用都会使用Redis作为计数的基础工具,它可以实现快速计数、 查询缓存的功能,同时数据可以异步落地到其他数据源。例如一些视频播放数系统就是使用Redis作为视频播放数计数的基础组件,用户每播放一次视频,相应的视频播放数就会自增1.

开发提示
实际上一个真实的计数系统要考虑的问题会很多:防作弊、按照不同维 度计数,数据持久化到底层数据源等。

3.共享Session

  一个分布式Web服务将用户的Session信息(例如用户登 录信息)保存在各自服务器中,这样会造成一个问题,出于负载均衡的考虑,分布式服务会将用户的访问均衡到不同服务器上,用户刷新一次访问可能会发现需要重新登录,这个问题是用户无法容忍的。为了解决这个问题,可以使用Redis将用户的Session进行集中管理,在这种模式下只要保证Redis是高可用和扩展性的,每次用户更新或者查询登录信息都直接从Redis中集中获取。

redissonClient操作APi redis常用api_缓存_20


4.限速

  很多应用出于安全的考虑,会在每次进行登录时,让用户输入手机验证 码,从而确定是否是用户本人。但是为了短信接口不被频繁访问,会限制用 户每分钟获取验证码的频率,例如一分钟不能超过5次。

redissonClient操作APi redis常用api_Redis_21

3:哈希

  几乎所有的编程语言都提供了哈希(hash)类型,它们的叫法可能是哈 希、字典、关联数组。在Redis中,哈希类型是指键值本身又是一个键值对 结构,形如value={{field1,value1},…{fieldN,valueN}},Redis键值对和 哈希类型二者的关系可以用下图来表示。

redissonClient操作APi redis常用api_redis_22


注:哈希类型中的映射关系叫作field-value,注意这里的value是指field对应 的值,不是键对应的值,请注意value在不同上下文的作用。

3.1:命令


1.设置值:hset key field value

redissonClient操作APi redis常用api_redis_23


此外Redis提供了hsetnx命令,它 们的关系就像set和setnx命令一样,只不过作用域由键变为field。


2.获取值:hget key field

redissonClient操作APi redis常用api_缓存_24


3.删除field:hdel key field [field …]

redissonClient操作APi redis常用api_redissonClient操作APi_25


4.计算field个数:hlen key

redissonClient操作APi redis常用api_缓存_26


5.批量设置或获取field-value

hmget key field [field ...] 
hmset key field value [field value ...]

redissonClient操作APi redis常用api_缓存_27


6.判断field是否存在:hexists key field


7.获取所有field:hkeys key
hkeys命令应该叫hfields更为恰当,它返回指定哈希键所有的field


8.获取所有value:hvals key


9.获取所有的field-value:hgetall key

redissonClient操作APi redis常用api_redis_28

提示:
在使用hgetall时,如果哈希元素个数比较多,会存在阻塞Redis的可能。 如果开发人员只需要获取部分field,可以使用hmget,如果一定要获取全部 field-value,可以使用hscan命令,该命令会渐进式遍历哈希类型,hscan将在后文介绍


10.hincrby hincrbyfloat

hincrby key field
hincrbyfloat key field

3.2:内部编码

哈希类型的内部编码有两种:

1.·ziplist(压缩列表): 当哈希类型元素个数小于hash-max-ziplist-entries 配置(默认512个)、同时所有值都小于hash-max-ziplist-value配置(默认64 字节)时,Redis会使用ziplist作为哈希的内部实现,ziplist使用更加紧凑的 结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。

2.hashtable(哈希表): 当哈希类型无法满足ziplist的条件时,Redis会使 用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,而 hashtable的读写时间复杂度为O(1)。

  当field个数比较少且没有大的value时,内部编码为ziplist:

redissonClient操作APi redis常用api_redissonClient操作APi_29


当有value大于64字节,内部编码会由ziplist变为hashtable:

redissonClient操作APi redis常用api_Redis_30

当field个数超过512,内部编码也会由ziplist变为hashtable:

redissonClient操作APi redis常用api_缓存_31


3.3:使用场景

图2-15为关系型数据表记录的两条用户信息,用户的属性作为表的列, 每条用户信息作为行。

如果将其用哈希类型存储,如图2-16所示。

redissonClient操作APi redis常用api_Redis_32


  相比于使用字符串序列化缓存用户信息,哈希类型变得更加直观,并且在更新操作上会更加便捷。可以将每个用户的id定义为键后缀,多对field- value对应每个用户的属性