Redis开发与运维读书笔记-第二章-字符串数据类型介绍(二)

下面从redis几种数据结构的角度来进行理解:

一.字符串

字符串是redis数据类型的基础,首先键都是字符串类型.字符串类型的值实际可以是字符串(简单的字符串、复杂的字符串(例如JSON、XML))、数字(整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过512MB

(一) 相关命令

常用命令:

(1)设置值(set key value [ex seconds] [px milliseconds] [nx|xx])

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

下面操作设置键为hello,值为world的键值对,返回结果为OK代表设置成功:

127.0.0.1:6379> set hello world 
OK

set命令有几个选项:
·ex seconds:为键设置秒级过期时间
·px milliseconds:为键设置毫秒级过期时间
·nx:键必须不存在,才可以设置成功,用于添加。
·xx:与nx相反,键必须存在,才可以设置成功,用于更新。
除了set选项,Redis还提供了setex和setnx两个命令:它们的作用和ex和nx选项是一样的。下面的例子说明了set、setnx、set xx的区别。

Redis开发与运维读书笔记-第二章-字符串数据类型介绍(二)_第1张图片

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

(2)获取值(get key)

Redis开发与运维读书笔记-第二章-字符串数据类型介绍(二)_第2张图片

(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)

要注意的是每次批 量操作所发送的命令数不是无节制的,如果数量过多可能造成Redis阻塞或者网络拥塞。

(5)计数(incr key)

incr命令用于对值做自增操作,返回结果分为三种情况:
·值不是整数,返回错误。
·值是整数,返回自增后的结果。
·键不存在,按照值为0自增,返回结果为1,继续对该键进行自增,返回2。

除了incr命令,Redis提供了decr(自减)、incrby(自增指定数字)、 decrby(自减指定数字)、incrbyfloat(自增浮点数)

不常用命令:

(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

下面操作返回结果为6,因为每个中文占用3个字节

127.0.0.1:6379> set hello "世界"
OK 
127.0.0.1:6379> strlen hello 
(integer) 6

(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

小结:

设值:set name zhangsan (说明:多次设置name会覆盖)
命令:
  setnx name lx: (not exist) 如果name不存在,则设值。如果name存在,则不设值并返回0;
  setex name 10 lx :(expired) 设置name的值为lx,过期时间为10秒,10秒后name清除(key也清除)
  setrange string range value 替换字符串
取值: get name
删值:del name
批量写:mset k1 v1 k2 v2 ...
批量读:mget k1 k2 k3
一次性设值和读取(返回旧值,写上新值):getset name lx
数值类型自增减:incr,decr,incrby,decrby
字符串拼接:append key value
字符串长度:strlen key

(二)内部编码

字符串类型的内部编码有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

(三)典型使用场景

1.缓存功能

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

Redis开发与运维读书笔记-第二章-字符串数据类型介绍(二)_第3张图片

下面伪代码模拟上图的访问过程:
1)该函数用于获取用户的基础信息:

UserInfo getUserInfo(long id){ ... }

2)首先从Redis获取用户信息

// 定义键 
userRedisKey = "user:info:" + id; 
// 从Redis获取值 
value = redis.get(userRedisKey); 
if (value != null) {    
// 将值进行反序列化为UserInfo并返回结果    
userInfo = deserialize(value);     
return userInfo; 
}

3)如果没有从Redis获取到用户信息,需要从MySQL中进行获取,并将 结果回写到Redis,添加1小时(3600秒)过期时间:

// 从MySQL获取用户信息 
userInfo = mysql.get(id); 
// 将userInfo序列化,并存入Redis 
redis.setex(userRedisKey, 3600, serialize(userInfo)); 
// 返回结果 
return userInfo

整个功能的伪代码如下:

UserInfo getUserInfo(long id){    
userRedisKey = "user:info:" + id ;   
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;
}

2.计数

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

long incrVideoCounter(long id) {    
    key = "video:playCount:" + id;    
    return redis.incr(key); 
}

3.共享Session

如下图所示,一个分布式Web服务将用户的Session信息(例如用户登录信息)保存在各自服务器中,这样会造成一个问题,出于负载均衡的考虑,分布式服务会将用户的访问均衡到不同服务器上,用户刷新一次访问可能会发现需要重新登录,这个问题是用户无法容忍的

Redis开发与运维读书笔记-第二章-字符串数据类型介绍(二)_第4张图片

为了解决这个问题,可以使用Redis将用户的Session进行集中管理,如下图所示,在这种模式下只要保证Redis是高可用和扩展性的,每次用户 更新或者查询登录信息都直接从Redis中集中获取。

Redis开发与运维读书笔记-第二章-字符串数据类型介绍(二)_第5张图片

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实现了限速功能,例如一些网站限制一个IP地址不 能在一秒钟之内访问超过n次也可以采用类似的思路
 

你可能感兴趣的:(读书笔记,redis字符串数据类型,字符串数据应用场景)