1、字符串
1.1 简介
字符串是Redis最基础的数据类型,其他的几种数据类型都是在字符串的基础上构建的。字符串类型的值实际上可以是字符串,数字,甚至可以是二进制的图片、音视频,但是其最大值为512M。
1.2 常用命令
(1)设置值
set key value [ex seconds] [px milliseconds] [nx|xx]
解析:
ex seconds : 为键设置秒级过期时间
px milliseconds: 为键设置毫秒级过期时间
nx:键必须不存在时才能设置成功,用于添加功能
xx:键必须存在才能设置成功,用于更新功能,与nx互斥存在。
除了set外,还提供了setex 和setnx两个命令,他们的作用和ex与nx的参数是一样的。
setex key secends value
setnx key value
示例:
# test键不存在
127.0.0.1:6379> exists test
(integer) 0
# set命令设置test键值为ttt
127.0.0.1:6379> set test ttt
OK
# setnx命令设置test,因为test键已经存在,所以设置失败,返回0
127.0.0.1:6379> setnx test tt1
(integer) 0
#set xx 更新test值为qqq
127.0.0.1:6379> set test qqq xx
OK
根据setnx的特性,多个客户端使用该命令时,只有一个客户端才能成功,所以setnx可以作为分布式锁的一种实现方案。
(2)获取值
# 如果key存在,返回对应的value,如果key不存在,返回nil
get key
(3)批量设置值
mset key value [key value ......]
#示例:
#通过mset一次性设置多个key-value对
127.0.0.1:6379> mset a 1 b 2 c 3
OK
(4)批量获取值
mget key [key ......]
#示例:
#通过mget获取 a、b、c的值
127.0.0.1:6379> mget a b c
1) "1"
2) "2"
3) "3"
#如果某些键不存在的话,会按照key的顺序返回nil
127.0.0.1:6379> mget a b c d
1) "1"
2) "2"
3) "3"
4) (nil)
(5)计数
incr key
incr命令用于对值做自增操作,返回结果有三种情况:
- 值不是整数,返回错误
- 值是整数,返回自增结果
- 键不存在,新增键值对,按照值为0自增,返回结果为1
除了incr命令,还有decr(自减)、incrby(自增指定数字)、decrby(自减指定数字)、incrbyfloat(自增浮点数)
decr key
incrby key increment
decrby key decrement
incrbyfloat key incrememt
1.3 内部编码
我们平时用到的数据结构是redis对外提供的数据结构类型,实际上在redis底层,每种数据结构都有对应独特的内部编码,下面介绍String的内部编码。
字符串在redis底层有三种编码类型,Redis会根据当前值的类型和长度决定使用那种内部编码实现,三种类型如下:
- int:8个字节的长整型
- embstr:小于等于39个字节的字符串
- raw:大于39个字节的字符串
示例:
#整型
127.0.0.1:6379> set k 11111111
OK
127.0.0.1:6379> object encoding k
"int"
#短字符串
127.0.0.1:6379> set x xxxxxxxxxx
OK
127.0.0.1:6379> object encoding x
"embstr"
#长字符串
127.0.0.1:6379> set y "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
OK
127.0.0.1:6379> object encoding y
"raw"
1.4 使用场景
(1)缓存功能
使用Redis作为缓存服务器使用,由于Redis具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用。下图是比较常见的缓存使用场景,使用mysql作为存储层,使用Redis作为缓存层,绝大部分数据从redis中返回,能大大提高web服务的响应时间。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k3V5TWAw-1650784188758)(imgs/image-20220221155007574.png)]
(2)计数器
目前许多服务都使用redis作为计数器的实现工具,redis能够实现快速计数功能,并且可以查询缓存,同时数据也可以异步写入到其他数据源中,比如网站的访问次数完全可以使用redis进行计数,每多一次访问,就自增1。
(3)token(session)共享
token(session)共享也是redis的一大使用场景,在微服务或者分布式web服务中,实现token(session)共享是一个十分重要的功能。当前端发起请求后,可能会分发到不同的服务中,如果没有实现token(session)共享,用户刷新后,有可能就会发现需要重新登录了,这是无法容忍的。
为了解决这个问题,可以引入redis,把session(token)统一管理起来,只要保证redis服务的高可用,就可以在每次请求时,集中从redis中获取token(session)。
2、哈希
2.1 简介
在Redis中,哈希类型指的是键对应的值本身又是一个键值对结构,形如value={{field1,value1},…{fieldN,valueN}}。哈希类型中的映射关系叫做field-value,这里的value是指field对应的值,不是键对应的值,如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6lmR3Ech-1650784188760)(imgs/image-20220221161406588.png)]
2.2 常用命令
(1)设置值
hset key field value
设置值时,如果设置成功,返回1,反之会返回0。此外Redis提供了hsetnx的命令,它的作用同setnx命令一样,只是作用域由键变成了field。
示例:
127.0.0.1:6379> hset user name candy
(integer) 1
(2)获取值
hget key field
如果键或field不存在的话,返回nil。
示例
127.0.0.1:6379> hget user name
"candy"
(3)删除field
hdel key field [field ......]
hdel会删除一个或多个field,返回结果为成功删除field的个数。
示例:
127.0.0.1:6379> hdel user name
(integer) 1
127.0.0.1:6379> hdel user city
(integer) 0
(4)计算field个数
hlen key
示例:
127.0.0.1:6379> hset user name tim
(integer) 1
127.0.0.1:6379> hlen user
(integer) 1
127.0.0.1:6379> hset user city beijing
(integer) 1
127.0.0.1:6379> hlen user
(integer) 2
(5) 批量设置field-value
hmset key field value [field value ......]
hmset需要的参数是key和多对field-value。
示例:
127.0.0.1:6379> hmset user age 12 set boy
OK
(6)批量获取field
hmget key field [field ......]
hmget需要的参数是key和多个field
示例:
127.0.0.1:6379> hmget user name age city set
1) "tim"
2) "12"
3) "beijing"
4) "boy"
(7) 判断field是否存在
hexists key field
hexists返回结果为1时说明包含field,否则返回为0
127.0.0.1:6379> hexists user name
(integer) 1
127.0.0.1:6379> hexists user xxx
(integer) 0
(8) 获取所有field
hkeys key
该命令返回的是键对应的所有field。
示例:
127.0.0.1:6379> hkeys user
1) "name"
2) "city"
3) "age"
4) "sex"
5) "set"
(9)获取所有的values
hvals key
(10)获取所有的field-value
hgetall key
(11)计算value的字符串长度
hstrlen key field
2.3 内部编码
哈希类型内部编码有两种:
- ziplist(压缩列表)
当哈希类型元素个数小于hash-max-ziplist-entries配置(默认512),同时所有值都小于hash-max-ziplist-value配置(默认64字节)时,Redis会使用ziplist作为哈希的内部实现,ziplist可以使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。
- hashtable(哈希表)
当hash类型无法满足ziplist的条件时,Redis就会使用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降。
示例:
# (1)当field个数比较少,并且没有大的value时,内部编码为ziplist
127.0.0.1:6379> hmset hk f1 v1 f2 v2 f3 v3
OK
127.0.0.1:6379> object encoding hk
"ziplist"
# (2) 当value值大于64时,内部编码就会变成hashtable
127.0.0.1:6379> hmset hk f4 "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
OK
127.0.0.1:6379> object encoding hk
"hashtable"
# (3)当field的个数超过512个时,内部编码也会变成hashtable
......
2.4 使用场景
缓存关系型数据库的信息。
以用户基本信息为例,相比使用字符串序列化后缓存用户信息,哈希类型变的更加直观,并且在更新操作上变的更加便捷,可以将每个用户的id定义为键或键后缀,多对field-value对应每个用户的字段信息。
关系型数据库与哈希类型的区别:
- 关系型数据库是完全结构化的数据,而hash是稀疏的,哈希类型每个键可以有完全不同的field,但是关系型数据库一旦添加新的字段,都需要为字段进行赋值。
- 关系型数据库可以做复杂的关联查询,Redis如果完成复杂的关系型查询,会十分困难。
3、对象类型数据的缓存
3.1 原生字符串
使用原生字符串缓存信息,每个属性一个键。示例如下:
set user.name tom
set user.city beijing
优点:简单直观,每个属性都能单独操作
缺点: 占用键过多,使用内存过多,同时信息内聚性太差。
3.2 序列化字符串
将对象信息先进行序列化操作,然后把序列化后的字符串用一个key保存。
优点:简单易用,合理规划对象的序列化,可以提高内存的使用效率
缺点:序列化和反序列化需要一定的资源,同时每次更新都需要把全部数据取出来进行操作。
3.3 哈希类型
每个对象属性使用一对field-value,但使用一个key进行存储
优点:简单直观,使用合理可以减少内存空间的使用
缺点:需要控制哈希在ziplist和hashtable两种内部编码的转换,hashtable会占用更多内存。