字符串类型是Redis最基础的数据结构。 首先键都是字符串类型, 而且其他几种数据结构都是在字符串类型基础上构建的, 所以字符串类型能为其
他四种数据结构的学习奠定基础。 如图2-7所示, 字符串类型的值实际可以是字符串(简单的字符串、 复杂的字符串(例如JSON、 XML) ) 、 数字
(整数、 浮点数) , 甚至是二进制(图片、 音频、 视频) , 但是值最大不能超过512MB。
1.常用命令
(1) 设置值
set key value [ex seconds] [px millisecconds] [nx|xx]
set命令有几个选项:
·ex seconds: 为键设置秒级过期时间。
·px milliseconds: 为键设置毫秒级过期时间。
·nx: 键必须不存在, 才可以设置成功, 用于添加。
·xx: 与nx相反, 键必须存在, 才可以设置成功, 用于更新。
除了set选项, Redis还提供了setex和setnx两个命令:
setex key seconds value
setnx key value
它们的作用和ex和nx选项是一样的。
当前键hello不存在:
127.0.0.1:6379> exists hello
(integer) 0
设置键为hello, 值为world的键值对:
127.0.0.1:6379> set hello world
OK
因为键hello已存在, 所以setnx失败, 返回结果为0:
127.0.0.1:6379> setnx hello redis
(integer) 0
因为键hello已存在, 所以set xx成功, 返回结果为OK:
127.0.0.1:6379> set hello jedis xx
OK
setnx和setxx在实际使用中有什么应用场景吗? 以setnx命令为例子, 由于Redis的单线程命令处理机制, 如果有多个客户端同时执行setnx key value,
根据setnx的特性只有一个客户端能设置成功, setnx可以作为分布式锁的一种实现方案, Redis官方给出了使用setnx实现分布式锁的方
法: http://redis.io/topics/distlock。
(2) 获取值
get key
下面操作获取键hello的值:
127.0.0.1:6379> get hello
"world
如果要获取的键不存在, 则返回nil(空) :
127.0.0.1:6379> get not_exist_key
(nil)
(3) 批量设置值
mset key value [key value ...]
下面操作通过mset命令一次性设置4个键值对:
127.0.0.1:6379> mset a 1 b 2 c 3 d 4
OK
(4) 批量获取值
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"
如果有些键不存在, 那么它的值为nil(空) , 结果是按照传入键的顺序返回:
127.0.0.1:6379> mget a b c f
1) "1"
2) "2"
3) "3"
4) (nil)
批量操作命令可以有效提高开发效率, 假如没有mget这样的命令, 要执行n次get命令需要按照图2-8的方式来执行, 具体耗时如下:
n次get时间 = n次网络时间 + n次命令时间
使用mget命令后, 要执行n次get命令操作只需要按照图2-9的方式来完成, 具体耗时如下:
n次get时间 = 1次网络时间 + n次命令时间
Redis可以支撑每秒数万的读写操作, 但是这指的是Redis服务端的处理能力, 对于客户端来说, 一次命令除了命令时间还是有网络时间, 假设网络
时间为1毫秒, 命令时间为0.1毫秒(按照每秒处理1万条命令算) , 那么执行1000次get命令和1次mget命令的区别如表2-1, 因为Redis的处理能力已经
足够高, 对于开发人员来说, 网络可能会成为性能的瓶颈。
学会使用批量操作, 有助于提高业务处理效率, 但是要注意的是每次批量操作所发送的命令数不是无节制的, 如果数量过多可能造成Redis阻塞或
者网络拥塞。
(5) 计数
incr key
incr命令用于对值做自增操作, 返回结果分为三种情况:
·值不是整数, 返回错误。
·值是整数, 返回自增后的结果。
·键不存在, 按照值为0自增, 返回结果为1。
例如对一个不存在的键执行incr操作后, 返回结果是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服务端都要顺序执行。
2.不常用命令
(1) 追加值
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"
(2) 字符串长度
strlen key
例如, 当前值为redisworld, 所以返回值为10:
127.0.0.1:6379> get key
"redisworld"
127.0.0.1:6379> strlen key
(integer) 10
(3) 设置并返回原值
getset key value
getset和set一样会设置值, 但是不同的是, 它同时会返回键原来的值,
例如:
127.0.0.1:6379> getset hello world
(nil)
127.0.0.1:6379> getset hello redis
"world"
(4) 设置指定位置的字符
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
(5) 获取部分字符串
getrange key start end
start和end分别是开始和结束的偏移量, 偏移量从0开始计算, 例如下面操作获取了值best的前两个字符。
127.0.0.1:6379> getrange redis 0 1
"be"
3.内部编码
字符串类型的内部编码有3种:
·int: 8个字节的长整型。
·emstr: 小于等于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
4.典型使用场景
1.缓存功能
图2-10是比较典型的缓存使用场景, 其中Redis作为缓存层, MySQL作为存储层, 绝大部分请求的数据都是从Redis中获取。 由于Redis具有支撑高
并发的特性, 所以缓存通常能起到加速读写和降低后端压力的作用。
2.计数
许多应用都会使用Redis作为计数的基础工具, 它可以实现快速计数、查询缓存的功能, 同时数据可以异步落地到其他数据源。
long incrVideoCounter(long id) {
key = "video:playCount:" + id;
return redis.incr(key);
}
3.共享Session
如图2-11所示, 一个分布式Web服务将用户的Session信息(例如用户登录信息) 保存在各自服务器中, 这样会造成一个问题, 出于负载均衡的考
虑, 分布式服务会将用户的访问均衡到不同服务器上, 用户刷新一次访问可能会发现需要重新登录, 这个问题是用户无法容忍的。
为了解决这个问题, 可以使用Redis将用户的Session进行集中管理, 如图2-12所示, 在这种模式下只要保证Redis是高可用和扩展性的, 每次用户
更新或者查询登录信息都直接从Redis中集中获取。
4.限速(频率控制)
很多应用出于安全的考虑, 会在每次进行登录时, 让用户输入手机验证码, 从而确定是否是用户本人。 但是为了短信接口不被频繁访问, 会限制用
户每分钟获取验证码的频率, 例如一分钟不能超过5次。
此功能可以使用Redis来实现:
phoneNum = "138xxxxxxxx";
key = "shortMsg:limit:" + phoneNum;
// SET key value EX 60 NX
isExists = redis.set(key,1,"EX 60","NX");
if(isExists != null || redis.incr(key) <=5){
// 通过
}else{
// 限速
}
备注:文章参考《Redis开发与运维》,作者:付磊,张益军