conanan's blog conanan's blog
首页
关于
  • 分类
  • 标签
  • 归档
  • Java
  • Java Web
  • 工具

    • Maven
  • MySQL
  • Redis
  • Git
  • Vim
  • Nginx
  • Docker
GitHub

Evan Xu

前端界的小学生
首页
关于
  • 分类
  • 标签
  • 归档
  • Java
  • Java Web
  • 工具

    • Maven
  • MySQL
  • Redis
  • Git
  • Vim
  • Nginx
  • Docker
GitHub
  • 基础

    • 简介
    • string
      • 介绍
      • 🔥KEY 的命名约定
      • 🔥SET为字符串键设置值
        • 可选参数 EX PX NX XX
      • SETNX/SETXX❗️改变覆盖规则
      • SETEX / PSETEX❗️设置过期时间
      • 🔥GET获取字符串键的值
      • GETSET 获取旧值并设置新值
      • 🔥MSET一次为多个字符串键设置值
      • MSETNX 键不存在的情况下批量设置值
      • 🔥MGET
      • SET 和 MSET 对比
      • STRLEN
      • GETRANGE 获取字符串值指定索引范围上的内容
      • SETRANGE 对字符串值的指定索引范围进行设置
      • APPEND 追加新内容到值的末尾
      • 🔥DEL所有类型都可删除
      • 🔥INCR / INCRBY / INCRBYFLOAT
      • DECR / DECRBY
      • ====================
      • 🔥【场景】分布式数据库主键 ID
      • 🔥【场景】限速器
      • 🔥【场景】密码错误限制
      • 🔥【场景】数据时效性
      • 主页高频访问信息显示控制思考
    • hash
    • list—顺序双向链表
    • set—大量数据
    • sorted_set—排序的大量数据
    • bitmap—位图
    • HyperLogLog
    • GEO—地理坐标
    • stream
    • 通用指令
    • Jedis
  • 高级

  • 集群

  • Redis面试
  • Redis
  • 基础
conanan
2021-06-21

string

# string

# 介绍

  • 字符串(string)键是Redis最基本的键值对类型,这种类型的键值对会在数据库中把单独的一个键和单独的一个值关联起来

  • 被关联的键和值既可以是普通的文字数据,也可以是图片、视频、音频、压缩文件等更为复杂的二进制数据

  • 如果字符串以整数的形式展示,可以作为数字操作使用,但本质还是字符串!

  • 数据最大存储量

    • 512MB,也不可能存储这么大的值!
  • 数值计算最大范围(java中的long的最大值)

    • 9223372036854775807
  • 数据操作不成功的反馈与数据正常操作之间的差异

    • 表示运行结果是否成功

      • (integer) 0 → false 失败
      • (integer) 1 → true 成功
    • 表示运行结果值

      • (integer) 3 → 3 3个
      • (integer) 1 → 1 1个
  • 数据未获取到

    • (nil)等同于null

# 🔥KEY 的命名约定

数据库中的热点数据key命名惯例

image-20210224235138080

# 🔥SET为字符串键设置值

设置即为添加、修改

set key value
1

实例

127.0.0.1:6379> set name conan
OK

127.0.0.1:6379> set name conanan
OK
1
2
3
4
5

# 可选参数 EX PX NX XX

从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:

  • EX seconds : 将键的过期时间设置为 seconds 秒。 执行 SET key value EX seconds 的效果等同于执行 SETEX key seconds value 。
  • PX milliseconds : 将键的过期时间设置为 milliseconds 毫秒。 执行 SET key value PX milliseconds 的效果等同于执行 PSETEX key milliseconds value 。
  • NX : 只在键不存在时, 才对键进行设置操作。 执行 SET key value NX 的效果等同于执行 SETNX key value 。
  • XX : 只在键已经存在时, 才对键进行设置操作。

提示

因为 SET 命令可以通过参数来实现 SETNX 、SETXX、 SETEX 以及 PSETEX 命令的效果, 所以 Redis 将来的版本可能会移除并废弃这几个命令。

# SETNX/SETXX❗️改变覆盖规则

  • NX:只会在键没有值的情况下执行设置操作,并返回OK表示设置成功;如果键已经存在,那么SET命令将放弃执行设置操作,并返回空值nil表示设置失败
  • XX:只会在键已经有值的情况下执行设置操作,并返回OK表示设置成功;如果给定的键并没有值,那么SET命令将放弃执行设置操作,并返回空值nil表示设置失败

# SETEX / PSETEX❗️设置过期时间

设置数据具有指定的生命周期

setex key seconds value  -- 秒
psetex key milliseconds value -- 毫秒
1
2

实例

127.0.0.1:6379> setex tel 3 110
OK
127.0.0.1:6379> get tel
"110"
127.0.0.1:6379> get tel
(nil)
1
2
3
4
5
6

但是记住,再次执行会重置时间,如:

127.0.0.1:6379> setex tel 3 110
OK
127.0.0.1:6379> setex tel 60 110 -- 重置为60秒
OK
127.0.0.1:6379> setex tel 110 -- 重置永久
OK
1
2
3
4
5
6

# 🔥GET获取字符串键的值

如果键 key 不存在, 那么返回特殊值 nil ; 否则, 返回键 key 的值。

如果键 key 的值并非string类型, 那么返回一个错误, 因为 GET 命令只能用于字符串值。

查询命令:

get key
1

查询一个存在的key:

127.0.0.1:6379> get name
"conanan"
1
2

查询一个不存在的key:

127.0.0.1:6379> get age
(nil)
1
2

Redis的数据库要求所有键必须拥有与之相关联的值,所以如果一个键有值,那么我们就说这个键存在于数据库;相反,如果一个键没有值,那么我们就说这个键不存在于数据库

# GETSET 获取旧值并设置新值

就像GET命令和SET命令的组合版本,GETSET首先获取字符串键目前已有的值,接着为键设置新值,最后把之前获取到的旧值返回给用户

GETSET key newValue
1

# 🔥MSET一次为多个字符串键设置值

添加、修改多个数据:

mset key1 value1 key2 value2 ...
1

其中m为 mutiple 多个意思

127.0.0.1:6379> mset a 1 b 2 c 3
OK
1
2

# MSETNX 键不存在的情况下批量设置值

略

# 🔥MGET

获取多个数据:

mget key1 key2 ...
1

实例

127.0.0.1:6379> mget a b c d
1) "1"
2) "2"
3) "3"
4) (nil) --注意这里
-- 注意整个返回的格式
1
2
3
4
5
6

# SET 和 MSET 对比

单数据操作与多数据操作的选择之惑

image-20210224232436229

基本上选择mset不会有问题,但是要注意实际数据大小!太少这俩没太大区别;太多太多也不能使用他俩,一条一条处理不行,单线程处理太多数据也不行,应该拆分数据后使用mset

# STRLEN

获取数据字符个数(字符串长度):

strlen key
1

实例

127.0.0.1:6379> get name
"conanan"
127.0.0.1:6379> strlen name
(integer) 7
127.0.0.1:6379>
1
2
3
4
5

注意中文:

127.0.0.1:6379> set c_name 哈哈
OK
127.0.0.1:6379> get c_name
"\xe5\x93\x88\xe5\x93\x88"
127.0.0.1:6379> strlen c_name
(integer) 6
1
2
3
4
5
6

# GETRANGE 获取字符串值指定索引范围上的内容

通过使用GETRANGE命令,用户可以获取字符串值从start索引开始,直到end索引为止的所有内容

GETRANGE key start end
1

GETRANGE命令接受的是闭区间索引范围

# SETRANGE 对字符串值的指定索引范围进行设置

通过使用SETRANGE命令,用户可以将字符串键的值从索引index开始的部分替换为指定的新内容,被替换内容的长度取决于新内容的长度:

SETRANGE key index substitute
1

# APPEND 追加新内容到值的末尾

追加信息到原始信息后部(如果原始信息存在就追加,否则新建):

append key value
1

注意:返回的是追加完毕后的长度!

127.0.0.1:6379> set name conanan
OK
127.0.0.1:6379> append name ' and lan'
(integer) 15
127.0.0.1:6379> get name
"conanan and lan"
1
2
3
4
5
6

# 🔥DEL所有类型都可删除

删除命令:

del key [key ...]
1

删除一个存在的key,返回影响的数量1:

127.0.0.1:6379> del name
(integer) 1
1
2

删除一个不存在的key,返回影响的数量0:

127.0.0.1:6379> del name
(integer) 0
1
2

删除多个

127.0.0.1:6379> set name a
OK
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> del name age
(integer) 2
1
2
3
4
5
6

# 🔥INCR / INCRBY / INCRBYFLOAT

设置数值数据增加指定范围的值(但是值为负数时即是减法操作)

incr key
incrby key increment 
incrbyfloat key increment
1
2
3

# DECR / DECRBY

设置数值数据减少指定范围的值(但是值为负数时即是加法操作)

decr key
decrby key increment
1
2

# ====================

# 🔥【场景】分布式数据库主键 ID

大型企业级应用中,分表操作是基本操作,使用多张表存储同类型数据,但是对应的主键 id 必须保证统一性 ,不能重复。Oracle 数据库具有 sequence 设定,可以解决该问题,但是 MySQL数据库并不具有类似的机制,那么如何解决?

可以利用 string 存储数字类型,并利用 incr 命令来生成主键id

string 作为数值操作注意:

  • string在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算。

  • redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发

    带来的数据影响。

  • 注意:按数值进行操作的数据,如果原始数据不能转成数值,或超越了redis 数值上限范围,将报错。 9223372036854775807(java中long型数据最大值,Long.MAX_VALUE)

结论:

  • redis用于控制数据库表主键id,为数据库表主键提供生成策略,保障数据库表的主键唯一性
  • 此方案适用于所有数据库,且支持数据库集群

# 🔥【场景】限速器

  • 为了防止网站内容被网络爬虫抓取,网站管理者通常会限制每个IP地址在固定时间段内能够访问的页面数量,比如1min之内最多只能访问30个页面,超过这一限制的用户将被要求进行身份验证,确认本人并非网络爬虫,或者等到限制解除之后再进行访问。
  • 为了防止用户的账号遭到暴力破解,网上银行通常会对访客的密码试错次数进行限制,如果一个访客在尝试登录某个账号的过程中,连续好几次输入了错误的密码,那么这个账号将被冻结,只能等到第二天再尝试登录,有的银行还会向账号持有者的手机发送通知来汇报这一情况。

实现这些限制机制的其中一种方法是使用限速器,它可以限制用户在指定时间段之内能够执行某项操作的次数。

  • 输入成功后需要重置!
  • 错误后减1即可

# 🔥【场景】密码错误限制

密码输入错误3次后,3小时后解封

解决方案

  • 设计计数器,记录调用次数,用于控制业务执行次数。以用户id作为key,使用次数作为value

  • 在调用前获取次数,判断是否超过限定次数

    • 不超过次数的情况下,每次调用计数+1
    • 业务调用失败,计数-1
  • 为计数器设置生命周期为指定周期,例如1秒/分钟,自动清空周期内使用次数

错误时调用

127.0.0.1:6379> get u:01
(nil)
127.0.0.1:6379> set u:01 1 ex 10 -- 设置超时时间
OK

127.0.0.1:6379> get u:01
"1" -- 若是大于等于限制次数,则之间返回,否则执行 incr
127.0.0.1:6379> incr u:01
(integer) 2
1
2
3
4
5
6
7
8
9

改进:

  • 取消最大值的判定,利用incr操作超过最大值抛出异常的形式替代每次判断是否大于最大值(但是存储占用会变大)

  • 判断是否为nil

    • 如果是,设置为Max-次数-1
    • 如果不是,计数+1
    • 业务调用失败,计数-1
  • 遇到异常即+操作超过上限,视为使用达到上限

# 🔥【场景】数据时效性

业务场景:

  • “最强女生”启动海选投票,只能通过微信投票,每个微信号每 4 小时只能投1票。
  • 电商商家开启热门商品推荐,热门商品不能一直处于热门期,每种商品热门期维持3天,3天后自动取消热门。
  • 新闻网站会出现热点新闻,热点新闻最大的特征是时效性,如何自动控制热点新闻的时效性。

通过SET的 ex 或px 参数控制数据的生命周期,通过数据是否失效控制业务行为,适用于所有具有时效性限定控制的操作

# 主页高频访问信息显示控制思考

例如新浪微博大V主页显示粉丝数与微博数量。解决如下(但是不推荐下面的存储格式):

  • 在redis中为大V用户设定用户信息,以用户主键和属性值作为key,后台设定定时刷新策略即可

    image-20210224235606470

  • 在redis中以json格式存储大V用户信息(不推荐),定时刷新(也可以使用hash类型,推荐)

    image-20210224235537410

编辑
上次更新: 2021/06/21, 15:45:42
简介
hash

← 简介 hash→

最近更新
01
线程生命周期
07-06
02
线程安全理论
06-24
03
并发简史
06-24
更多文章>
Theme by Vdoing | Copyright © 2019-2021 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×