目录
String
命令小结
内部编码
典型的使用场景
缓存功能
计数功能
共享会话
手机验证码
Hash 哈希
命令
hset
hget
hexists
hdel
hkeys
hvals
hgetall
hmget
hlen
hsetnx
hincrby
hincrbyfloat
String
上一篇中介绍了了String里的基本命令, 接下来总结一下
命令小结
命令 | 执行效果 | 时间复杂度 |
set key value [key value...] | 设置key的值为value | O(1) |
get key | 获取指定的key值 | O(1) |
del key[key...] | 删除指定的key | O(k), k是键的个数 |
mset key value[key value...] | 批量设置指定的key和value | O(k), k是键的个数 |
mget key [key...] | 批量获取key的值 | O(k). k是键的个数 |
incr key | 指定的key值 + 1 | O(1) |
decr key | 指定的key值 - 1 | O(1) |
incrby key n | 指定的key值 + n | O(1) |
decrby key n | 指定的key值 - n | O(1) |
incrbyfloat key n | 指定的key值 + n | O(1) |
append key value | 指定的key值追加value | O(1) |
strlen key | 获取指定key的长度 | O(1) |
setrange key offset value | 覆盖指定key的从offset开始的部分值 | O(n), n是字符串长度, 通常视为O(1) |
getrange key start end | 获取指定的key的从start到end的部分值 | O(n),n是字符串长度, 通常视为O(1) |
内部编码
字符串的内部编码有3种:
int : 8个字节的长整型.
embstr: 小于等于39个字节的字符串.
raw: 大于39个字节的字符串.
示例:
典型的使用场景
缓存功能
下图是比较典型的缓存使用场景, 其中Redis作为缓冲层, MySQL作为存储层, 绝大部分的请求数据都是从Redis中获取. 由于Redis具有支持高并发的特性, 所以缓存通常能起到加速读写和降低后端压力的作用.
流程如下:
(1)用户访问业务层, 查找想要的数据
(2)业务层对缓存层进行查询
(3)如果缓存层查询到数据, 则直接返回给业务层
(4)如果缓存层未查找到, 就从存储层获取
(5)从存储层获取到之后返回给缓存层, 并把该数据写入缓存层
(6)缓存层再将该数据返回给业务层
通过增加缓存功能, 在理想情况下, 每个用户信息, 一个小时期间只有一次MySQL查询, 极大地提升了查询效率, 也降低了MySQL的访问数.
计数功能
许多应用都会使用Redis作为计数的基础工具, 它可以实现快速计数, 查询缓存的功能, 同时数据可以异步处理或者落地到其它数据源. 例如视频播放网站播放次数可以使用Redis完成: 每播放一次视频, 相应的视频播放次数就会自增1.
实际中要开发一个成熟, 稳定的计数系统, 要面临的挑战远不止如此简单: 防作弊, 按不同维度计数, 避免单点问题, 数据持久化到底层数据源等问题.
共享会话
如图: 一个分布式web服务将用户的Session信息(例如用户登录信息)保存在各自的服务器中, 但这样会造成一个问题: 处于负载均衡的考虑, 分布式服务会将用户的访问请求均衡到不同的服务器上,并且通常无法保证用户每次请求都会被均衡到同一台服务器上, 这样用户每刷新一次访问是可能会发现需要重新登录, 这个问题是无法容忍的.
session分散存储:
为了解决这个问题, 可以使用Redis将用户的Session信息进行集中管理, 如图, 在这种模式下, 只要保证Redis是高可用和扩展性的, 无论用户被均衡到哪台Web服务器上, 都集中从Redis中查询, 更新Session信息.
Redis集中管理Session:
手机验证码
很多应用出于安全考虑, 会在每次登陆时, 让用户输入手机号并配合给手机发送验证码, 然后让用户再次输入收到的验证码并进行验证, 从而确定是否是用户本人. 为了短信接口不会被频繁访问, 会限制用户获取验证码的频率. 比如一分钟一次.
思路: 使用带过期时间的键, 并设置其过期时间60s, 如果每次发送时该键存在,就会被限制发送, 具体实现就不过多展开了, 老铁们如果感兴趣可以自行查询.
Hash 哈希
几乎所有的主流编程语言都提供了哈希类型, 它们的叫法可能是哈希, 字典, 关联数组, 映射. 说到这, 有的人就会问了, 这Redis本身不就是哈希表么, 怎么又套了一个? 其实是这样实现的: 形如key = "key", value = {{field1, value1},...,{fieldN, valueN}}
字符串类型和哈希类型的对比:
哈希类型中的映射关系通常称为field-value, 用于区分Redis整体的键值对(key-value), 注意这里的value是指field所对应的值, 不是键(key)对应的值, 请注意value在不同上下文中的作用.
命令
hset
设置hash中指定的字段(field)的值(value).
语法:
hset key field value [field value...]
命令有效版本: 2.0.0之后
时间复杂度: 插入一组field为O(1), 插入N组field为O(N).
返回值: 添加的字段个数.
示例:
hget
获取hash中指定字段的值.
语法:
hget key field
命令有效版本: 2.0.0
时间复杂度: O(1)
返回值: 字段对应的值或者是nil.
hexists
判断hash中是否有指定的字段.
语法:
hexists key field
命令有效版本: 2.0.0之后.
时间复杂度: O(1)
返回值: 1表示存在, 0表示不存在
示例:
hdel
删除hash中的指定字段.
语法:
hdel key field [field ...]
命令有效版本: 2.0.0之后
时间复杂度: 删除一个元素为O(1). 删除N个元素为O(N).
返回值: 本次操作删除的字段个数.
示例:
hkeys
获取hash中的所有字段.
语法:
hkeys key
命令有效版本: 2.0.0之后.
时间复杂度: O(N), N为field个数.
返回值: 字段列表
示例:
hvals
获取hash中的所有值.
语法:
hvals key
命令有效版本: 2.0.0之后
时间复杂度: O(N), N为field个数.
返回值: 所有的值.
示例:
hgetall
获取hash中所有字段以及对应的值.
语法:
hgetall key
命令有效版本: 2.0.0之后
时间复杂度: O(N), N为field个数
返回值: 字段和对应的值.
示例:
hmget
一次获取hash中多个字段的值.
语法:
hmget key field [field ...]
命令有效版本: 2.0.0之后
时间复杂度: 只查询一个元素为O(1), 查询多个元素为O(N), N为查询元素个数.
返回值: 字段对应的值或者nil.
示例:
hlen
获取hash中所有字段的个数.
语法:
hlen key
命令有效版本: 2.0.0之后
时间复杂度: O(1)
返回值: 字段个数.
hsetnx
在字段不存在的情况下, 设置hash中的字段和值.
语法:
hsetnx key field value
命令有效版本: 2.0.0之后
时间复杂度: O(1)
返回值: 1表示成功, 0 表示失败
示例:
hincrby
将hash中字段对应的数值添加指定的值.
语法:
hincrby key field increment
命令有效版本: 2.0.0之后
时间复杂度: O(1)
返回值: 该字段变化后的值.
示例:
hincrbyfloat
hincrby的浮点数版本, 不过多解释.