字符串类型 是 Redis 最基础的数据结构。字符串类型 的值实际能够是 字符串(简单 和 复杂 的字符串,例如 JSON、XML)、数字(整数、浮点数),甚至是 二进制(图片、音频、视频),可是值最大不能超过 512MB。java
set key value [ex seconds] [px milliseconds] [nx|xx]
set 命令有几个选项:mysql
ex seconds:为 键 设置 秒级过时时间。web
px milliseconds:为 键 设置 毫秒级过时时间。redis
nx:键必须 不存在,才能够设置成功,用于 添加。sql
xx:与 nx 相反,键必须 存在,才能够设置成功,用于 更新。编程
除了 set 选项,Redis 还提供了 setex 和 setnx 两个命令:后端
setex key seconds value setnx key value
setex:设定键的值,并指定此键值对应的 有效时间。缓存
127.0.0.1:6379> setex key1 5 value1 OK 127.0.0.1:6379> get key1 "value1" 127.0.0.1:6379> get key1 (nil)
setnx:键必须 不存在,才能够设置成功。若是键已经存在,返回 0。安全
127.0.0.1:6379> set key2 value1 OK 127.0.0.1:6379> setnx key2 value2 (integer) 1 127.0.0.1:6379> get key2 "value1"
get key
若是要获取的 键不存在,则返回 nil(空)。服务器
127.0.0.1:6379> get not_exist_key (nil)
mset key value [key value ...]
下面操做经过 mset 命令一次性设置 4 个 键值对:
127.0.0.1:6379> mset a 1 b 2 c 3 d 4 OK
mget key [key ...]
经过下面操做 批量获取 键 a、b、c、d 的值:
127.0.0.1:6379> mget a b c d 1) "1" 2) "2" 3) "3" 4) "4"
批量操做 命令,能够有效提升 开发效率,假如没有 mget 这样的命令,要执行 n 次 get 命令的过程和 耗时 以下:
n次get时间 = n次网络时间 + n次命令时间
使用 mget 命令后,执行 n 次 get 命令的过程和 耗时 以下:
n次get时间 = 1次网络时间 + n次命令时间
Redis 能够支撑 每秒数万 的 读写操做,但这指的是 Redis 服务端 的处理能力,对于 客户端 来讲,一次命令除了 命令时间 仍是有 网络时间。
假设 网络时间 为 1 毫秒,命令时间为 0.1 毫秒(按照每秒处理 1 万条命令算),那么执行 1000 次 get 命令和 1 次 mget 命令的区别如表所示:
操做 | 时间 |
---|---|
1000次get操做 | 1000 * 1 + 1000 * 0.1 = 1100ms = 1.1s |
1次mget操做 | 1 * 1 + 1000 * 0.1 = 101ms = 0.101s |
incr key
incr 命令用于对值作 自增操做,返回结果分为三种状况:
值不是 整数,返回 错误。
值是 整数,返回 自增 后的结果。
键不存在,按照值为 0 自增,返回结果为 1。
127.0.0.1:6379> exists key (integer) 0 127.0.0.1:6379> incr key (integer) 1 复制代码
除了 incr 命令,Redis 还提供了 decr(自减)、incrby(自增指定数字)、decrby(自减指定数字)、incrbyfloat(自增浮点数)等命令操做:
decr key
incrby key increment
decrby key decrement
incrbyfloat key increment
不少 存储系统 和 编程语言 内部使用 CAS 机制实现 计数功能,会有必定的 CPU 开销。但在 Redis 中彻底不存在这个问题,由于 Redis 是 单线程架构,任何命令到了 Redis 服务端 都要 顺序执行。
append key value
append 能够向 字符串尾部 追加值。
127.0.0.1:6379> get key "redis" 127.0.0.1:6379> append key world (integer) 10 127.0.0.1:6379> get key "redisworld"
strlen key
好比说,当前值为 redisworld,因此返回值为 10:
127.0.0.1:6379> get key "redisworld" 127.0.0.1:6379> strlen key (integer) 10
getset key value
getset 和 set 同样会 设置值,可是不一样的是,它同时会返回 键原来的值,例如:
127.0.0.1:6379> getset hello world (nil) 127.0.0.1:6379> getset hello redis "world"
setrange key offeset value
下面操做将值由 pest 变为了 best:
127.0.0.1:6379> set redis pest OK 127.0.0.1:6379> setrange redis 0 b (integer) 4 127.0.0.1:6379> get redis "best"
getrange key start end
start 和 end 分别是 开始 和 结束 的 偏移量,偏移量 从 0 开始计算,例如获取值 best 的 前两个字符 的命令以下:
127.0.0.1:6379> getrange redis 0 1 "be"
最后给出 字符串 类型命令的 时间复杂度 说明:
字符串 类型的 内部编码 有 3 种:
int:8 个字节的 长整型。
embstr:小于等于 39 个字节的字符串。
raw:大于 39 个字节的字符串。
Redis 会根据当前值的 类型 和 长度 决定使用哪一种 内部编码实现。
整数类型
127.0.0.1:6379> set key 8653 OK 127.0.0.1:6379> object encoding key "int"
短字符串
小于等于39个字节的字符串:embstr
127.0.0.1:6379> set key "hello,world" OK 127.0.0.1:6379> object encoding key "embstr"
长字符串
大于39个字节的字符串:raw
127.0.0.1:6379> set key "one string greater than 39 byte........." OK 127.0.0.1:6379> object encoding key "raw" 127.0.0.1:6379> strlen key (integer) 40
下面是一种比较典型的 缓存 使用场景,其中 Redis 做为 缓存层,MySQL 做为 存储层,绝大部分请求的数据都是从 Redis 中获取。因为 Redis 具备支撑 高并发 的特性,因此缓存一般能起到 加速读写 和 下降后端压力 的做用。
整个功能的伪代码以下:
public UserInfo getUserInfo(long id) { String userRedisKey = "user:info:" + id; String value = redis.get(userRedisKey); UserInfo userInfo; if (value != null) { userInfo = deserialize(value); } else { userInfo = mysql.get(id); if (userInfo != null) { redis.setex(userRedisKey, 3600, serialize(userInfo)); } return userInfo; } }
许多应用都会使用 Redis 做为 计数 的基础工具,它能够实现 快速计数、查询缓存 的功能,同时数据能够 异步落地 到其余 数据源。通常来讲,视频播放数系统,就是使用 Redis 做为 视频播放数计数 的基础组件,用户每播放一次视频,相应的视频播放数就会自增 1。
public long incrVideoCounter ( long id){ String key = "video:playCount:" + id; return redis.incr(key); }
实际上,一个真实的 计数系统 要考虑的问题会不少:防做弊、按照 不一样维度 计数,数据持久化 到 底层数据源等。
一个 分布式 Web 服务将用户的 Session 信息(例如 用户登陆信息)保存在 各自 的服务器中。这样会形成一个问题,出于 负载均衡 的考虑,分布式服务 会将用户的访问 均衡 到不一样服务器上,用户 刷新一次访问 可能会发现须要 从新登陆,这个问题是用户没法容忍的。
为了解决这个问题,可使用 Redis 将用户的 Session 进行 集中管理。在这种模式下,只要保证 Redis 是 高可用 和 扩展性的,每次用户 更新 或者 查询 登陆信息都直接从 Redis 中集中获取。
不少应用出于安全的考虑,会在每次进行登陆时,让用户输入 手机验证码,从而肯定是不是用户本人。可是为了 短信接口 不被 频繁访问,会 限制 用户每分钟获取 验证码 的频率。例如一分钟不能超过 5 次,如图所示:
此功能可使用 Redis 来实现,伪代码以下:
String phoneNum = "138xxxxxxxx"; String key = "shortMsg:limit:" + phoneNum; // SET key value EX 60 NX boolean isExists = redis.set(key, 1, "EX 60", "NX"); if (isExists != null || redis.incr(key) <= 5) { // 经过 } else { // 限速 }
上述就是利用 Redis 实现了 限速功能,例如 一些网站 限制一个 IP 地址不能在 一秒钟以内 访问超过 n 次也能够采用 相似 的思路。
本文简单的介绍了 Redis 的 字符串数据结构 的 基本命令,内部编码 和 相关应用场景。