数据库|redis开发与运维读书笔记(第二章)

2.1 预备 2.1.1 全局命令

  1. keys *:查询所有的key,遍历所有的key,时间复杂度为O(n)。当数据量很大时,会非常慢,线上不建议使用;
  2. dbsize:返回所拥有的key的数量。redis内部有一个记录当前key数量的值,因此时间复杂度为O(1)
  3. exists:检查key是否存在;
  4. del:删除指定的key,可批量操作;
  5. expire:设置过期时间;
  6. ttl:返回key的剩余存货时间,或者-1(key没有设置过期时间),-2(key不存在)
  7. type:返回key的类型
2.1.2 数据结构和内部编码
redis一共有五种数据结构:String, Hash, Set, Sorted Set, List
可以使用object encoding命令,来分别查看key的内部编码
数据库|redis开发与运维读书笔记(第二章)
文章图片

2.1.3 单线程架构
  1. 由于redis是单线程架构,因此不会存在并发问题/
  2. 为什么单线程还那么快?
  • 单线程避免了线程切换产生的开销;
  • redis是异步非阻塞IO;
  • redis是纯内存操作,这个比磁盘操作要快很多。
  1. 某个命令过长的情况:由于redis是单线程,当某个命令过长的时候,会让其它命令等待时间很长,这种情况应该避免。
2.2 字符串 2.2.1 命令
1. 常用命令
  1. 设置值
  • set key value [ex seconds] [px milliseconds] [nx|xx]
  • setxx
  • setnx:应用场景:分布式锁
  1. 获取值
  • get key
  1. 批量设置,获取值
  • mset key value [key value ...]
  • mget key [key ...]
  1. 使用批量操作和非批量操作的时间消耗:
  • 非批量操作:n次get时间 = n次网络时间 + n次命令时间
    数据库|redis开发与运维读书笔记(第二章)
    文章图片
  • 批量操作:n次get时间 = 1次网络时间 + n次命令时间
    数据库|redis开发与运维读书笔记(第二章)
    文章图片
  1. 计数
  • incr key
  • decr key
  • incrby
  • decrby
2.2.2 内部编码
int, embstr, raw
2.2.3 典型应用场景
  1. 缓存:获取用户信息时,我们可以将用户信息存放在redis中,这样子就避免了下一次读取用户信息时,还得从磁盘读取。伪代码如下:
    public UserInfo getUser(long userId) { String userKey = "user_info_" + userId; UserInfo userInfo = redis.get(userKey); if(userInfo == null) { userInfo = db.get(userKey); //设置一个小时的过期时间 redis.setex(userKey, 3600, serialize(userInfo)); } return deserialize(userInfo); }

  2. 计数
    public long incrCount(long userId) { String key = "user_counter_" + userId; redis.incr(key); }

  3. 限速:这个我们的生活中常常能碰到,例如,短信验证码一分钟内最多只能发送五次。
    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 { // 限速 }

2.3 哈希
2.3.1 命令
  1. 设置值:hset key field value
  2. 获取值:hget key field
  3. 删除field:hdel key field [field ... ]
  4. 计算field个数:hlen key
  5. 批量设置,获取field:hmget key field [field ...]
    mset key field value [field value ...]
  6. 判断key是否存在:hexists key field
  7. 获取所有的field:hkeys key
  8. 获取所有的value:hvals key
  9. 获取所有的key-value:hgetall key
2.3.2 内部编码
  1. ziplist
  2. hashtable
2.3.3 应用场景 存储用户信息:下面这张图体现了数据库和redis存储用户信息时的差异,redis看起来更加清晰。而且,当数据库表的字段增加一列的时候,所有的用户都必须为这一列增加新的值,redis更为灵活。
数据库|redis开发与运维读书笔记(第二章)
文章图片

使用redis添加用户信息的伪代码:
public UserInfo getUserInfo(long userId) { String userKey = "user:info:" + userId; userInfoMap = redis.hgetAll (userKey); //取出用户的所有信息 if(userInfomAP != null) { UserInfo userInfo = transferMapToInfo(userInfoMap); //将map转换为UserInfo } else { userInfo = db.get(id); redis.hset(userKey, transferInfoToMap(userInfo)); redis.expire(userKey, 3600); } }

2.4 列表
2.4.1 命令
  1. 添加命令:
  • 从右边添加元素:rpush key value [value ...]
  • 从左边添加元素:lpush key value [value ...]
  • 从指定位置添加元素:linsert key before|after pivot value
  1. 查找:
  • 获取指定范围内的元素:lrange key start end
  • 获取指定下标的元素:lindex key index;index = -1代表最后一个
  • 获取列表长度:llen key
  • 从左侧弹出:lpop
  • 从右侧弹出:rpop
  • 删除指定元素:lrem key count value,删除指定元素value,最多删除count个。count > 0,从左开始; count < 0,从右开始, count = 0,删除所有。
  • 按照范围裁剪列表:ltrim key start end
  • 修改指定下标元素:lset key index newValue
2.4.2 数据结构
  1. ziplist
  2. linkedlist
  3. quicklist
2.4.3 应用场景 文章列表
2.5 集合
2.5.1 命令
  1. 集合内操作
  • 添加元素:sadd key element [element ...]
  • 删除元素:srem key element [element...]
  • 查询大小:scard key
  • 随机返回指定个数:srandmember key [count]
  • 从集合随机弹出元素:spop key
  • 获取所有元素:smembers key
  1. 集合间的操作
  • 求交集:sinter key [key...]
  • 求并集:sunion key [key..]
  • 求差集:sdiff key [key...]
  • 上面三个命令后缀加store,可以将得到的结果存储起来,例如:sinterstore user1_2inter user:1:follow user:2:follow
2.5.2 内部编码
  1. intset:元素较少且均为整数
  2. hashtable
2.5.3 应用场景 给用户添加标签
2.6 有序集合
2.6.1 命令
  1. 集合内
  • 添加成员:zadd key score memeber [score member...]
  • 计算成员个数:zcard key
  • 计算某个成员的分数:zcore key member
  • 计算某个成员排名:
    低到高:zrank key member
    高到低:zrevrank key member
  • 删除成员:zrem key member
  • 给指定成员增加分数:zincrby key increment member
2.6.2 内部编码
  1. ziplist
  2. skiplist
2.6.3 应用场景 【数据库|redis开发与运维读书笔记(第二章)】排行榜

    推荐阅读