【Redis】String的常用命令及图解String使用场景

本文将详细介绍 Redis String 类型的常见命令及其使用场景,包括缓存、计数器、共享会话、手机验证码、分布式锁等场景,并且配图和伪代码进一步方便理解和使用。

命令执行效果时间复杂度
set key value [key value…]设置key的值是valueO(k),k是键个数
get key获取key的值O(1)
del key [key …]删除指定的keyO(k),k是键个数
mset key value [key value …]批量设置指定的key和valueO(k),k是键个数
mget key [key …]批量获取key的值O(k),k是键个数
incr key指定的key的值+1O(1)
decr key指定的key的值-1O(1)
incrby key n定的key的值+nO(1)
decrby key n指定的key的值-nO(1)
incrbyfloat key n指定的key的值+nO(1)
append key value指定的key的值追加valueO(1)
strlen key获取指定key的值的长度O(1)

setrange key offset value

覆盖指定key的从offset开始的部分值

O(n),n是字符串长度,通常视为0(1)

getrange key start end

获取指定key的从start到end的部分值

O(n),n是字符串长度,通常视为O(1)

 1. 相关命令演示

# SET 命令
# 设置 key1 的值为 "Hello"
# 时间复杂度: O(1)
127.0.0.1:6379> SET key1 "Hello"
OK

# 设置 key2 的值为 "Redis"
# 时间复杂度: O(1)
127.0.0.1:6379> SET key2 "Redis"
OK

# GET 命令
# 获取 key1 的值
# 时间复杂度: O(1)
127.0.0.1:6379> GET key1
"Hello"

# DEL 命令
# 删除 key1
# 时间复杂度: O(1) 对单个键
127.0.0.1:6379> DEL key1
(integer) 1

# 尝试获取已经被删除的 key1 的值
# 时间复杂度: O(1)
127.0.0.1:6379> GET key1
(nil)

# MSET 命令
# 批量设置多个键值对
# 时间复杂度: O(k), k 是键的个数
127.0.0.1:6379> MSET key1 "Hello" key2 "Redis" key3 "!"
OK

# MGET 命令
# 批量获取多个键的值
# 时间复杂度: O(k), k 是键的个数
127.0.0.1:6379> MGET key1 key2 key3
1) "Hello"
2) "Redis"
3) "!"

# INCR 命令
# 将 counter 的值加 1
# 时间复杂度: O(1)
127.0.0.1:6379> SET counter 10
OK
127.0.0.1:6379> INCR counter
(integer) 11

# DECR 命令
# 将 counter 的值减 1
# 时间复杂度: O(1)
127.0.0.1:6379> DECR counter
(integer) 10

# INCRBY 命令
# 将 counter 的值加 5
# 时间复杂度: O(1)
127.0.0.1:6379> INCRBY counter 5
(integer) 15

# DECRBY 命令
# 将 counter 的值减 3
# 时间复杂度: O(1)
127.0.0.1:6379> DECRBY counter 3
(integer) 12

# INCRBYFLOAT 命令
# 将 counter 的值加 2.5(浮点数)
# 时间复杂度: O(1)
127.0.0.1:6379> INCRBYFLOAT counter 2.5
"14.5"

# APPEND 命令
# 将 " World" 追加到 key1 的值后
# 时间复杂度: O(1)
127.0.0.1:6379> APPEND key1 " World"
(integer) 11
127.0.0.1:6379> GET key1
"Hello World"

# STRLEN 命令
# 获取 key1 的值的长度
# 时间复杂度: O(1)
127.0.0.1:6379> STRLEN key1
(integer) 11

# SETRANGE 命令
# 从偏移量 6 开始,将 key1 的值替换为 "Redis"
# 时间复杂度: O(n),n 是字符串的长度,通常视为 O(1)
127.0.0.1:6379> SET key1 "Hello World"
OK
127.0.0.1:6379> SETRANGE key1 6 "Redis"
(integer) 11
127.0.0.1:6379> GET key1
"Hello Redis"

# GETRANGE 命令
# 获取 key1 从偏移量 0 到 4 的部分值
# 时间复杂度: O(n),n 是字符串的长度,通常视为 O(1)
127.0.0.1:6379> GETRANGE key1 0 4
"Hello"

2. 内部编码

Redis 中的字符串(String)类型是最基本的数据类型。为了高效地存储和操作字符串数据,Redis对字符串类型进行了多种内部编码优化。具体来说,字符串的内部编码主要有以下三种:intembstrraw。

int:8 个字节的⻓整型。
embstr:⼩于等于 39 个字节的字符串。 【Redis 3.2 及之前版本
raw:⼤于 39 个字节的字符串。 【Redis 3.2 及之前版本

Redis 4.0 及之后版本

  • embstr 编码:用于长度小于等于 44 字节的字符串。
  • raw 编码:用于长度大于 44 字节的字符串。

2.1 int

当一个字符串的值可以表示为 64 位(8字节)带符号整数时,Redis 会将该字符串编码为 int 类型。这种编码方式节省了内存,并且可以更高效地执行诸如 INCRDECR 等操作。

127.0.0.1:6379> SET myint 100
OK
127.0.0.1:6379> OBJECT ENCODING myint
"int"

2.2. embstr

当字符串的长度小于等于 44 字节时,Redis 会使用 embstr 编码。这种编码将 Redis 对象和实际字符串数据存储在连续的内存块中,因此在内存分配和访问上更加高效。embstr 编码在创建时效率很高,但一旦需要修改字符串内容,它会转换为 raw 编码。

127.0.0.1:6379> SET shortstr "Hello, Redis!"
OK
127.0.0.1:6379> OBJECT ENCODING shortstr
"embstr"

2.3 raw

当字符串长度大于 44 字节或需要进行修改操作时,Redis 会使用 raw 编码。raw 编码将 Redis 对象和字符串数据分开存储。这种方式适用于较长字符串或频繁修改的字符串,因为在这种情况下,内存分配和管理会更加高效。

127.0.0.1:6379> SET longstr "This is a very long string that exceeds the embstr limit."
OK
127.0.0.1:6379> OBJECT ENCODING longstr
"raw"

来看一下我使用的版本

 验证一下是39字节还是44字节发生内部编码类型的变化

测试长度为 39 字节的字符串

 测试长度为 44 字节的字符串

测试长度为 45 字节的字符串

 3 典型使用场景

3.1 缓存(Cache)功能

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

 下面的伪代码模拟了图 2-10 的业务数据访问过程

1. 假设业务是根据用户 uid 获取用户信息

UserInfo getUserInfo(long uid) {
 ...
}

2. 首先从 Redis 获取用户信息,我们假设用户信息保存在"user:info:<uid>" 对应的键中

1 // 根据 uid 得到 Redis 的键
2 String key = "user:info:" + uid;
3
4 // 尝试从 Redis 中获取对应的值
5 String value = Redis 执行命令:get key;
7 // 如果缓存命中(hit)
8 if(value != null){
9     //假设我们的用户信息按照 JSON 格式存储
10    UserInfo userInfo = JSON 反序列化(value);
11    return userInfo:
12 }

3. 如果没有从 Redis 中得到用户信息,及缓存 miss,则进一步从 MVSOL中获取对应的信息,随后写入缓存并返回:

// 如果缓存未命中(miss)
if (value == null) {
     // 从数据库中,根据 uid 获取⽤⼾信息
     UserInfo userInfo = MySQL 执⾏ SQL:select * from user_info where uid = <uid>
 
     // 如果表中没有 uid 对应的⽤⼾信息
     if (userInfo == null) {
         响应 404
         return null;
     }
 
     // 将⽤⼾信息序列化成 JSON 格式
     String value = JSON 序列化(userInfo);
 
     // 写⼊缓存,为了防⽌数据腐烂(rot),设置过期时间为 1 ⼩时(3600 秒)
     Redis 执⾏命令:set key value ex 3600
 
     // 返回⽤⼾信息
     return userInfo;
}

3.2 计数器功能

许多应用都会使用 Redis 作为计数的基础工具,它可以实现快速计数、查询缓存的功能,同时数据可以异步处理或者落地到其他数据源。如下图所示,例如视频网站的视频播放次数可以使用Redis 来完成:用户每播放一次视频,相应的视频播放数就会自增 1

 3.3 共享会话

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

为了解决这个问题,可以使用 Redis 将用户的 Session 信息进行集中管理,如下图所示,在这种模式下,只要保证 Redis 是高可用和可扩展性的,无论用户被均衡到哪台 Web 服务器上,都集中从Redis 中查询、更新 Session 信息。

3.4 手机验证码

很多应用出于安全考虑,会在每次进行登录时,让用户输入手机号并且配合给手机发送验证码,然后让用户再次输入收到的验证码并进行验证,从而确定是否是用户本人。为了短信接口不会频繁访会限制用户每分钟获取验证码的频率,例如一分钟不能超过5次,如图所示。

 此功能可以⽤以下伪代码说明基本实现思路

// 发送验证码并处理发送频率限制
String 发送验证码(String phoneNumber) {
    // 构造用于限制短信发送频率的 Redis 键
    String key = "shortMsg:limit:" + phoneNumber;

    // 尝试在 Redis 中设置键值对,设置过期时间为 1 分钟(60 秒),只在键不存在时才能成功(NX 参数)
    boolean r = Redis.执行命令:set key 1 ex 60 nx;

    if (!r) {
        // 如果设置失败,说明之前已经设置过该手机号的发送频率限制
        // 增加计数器,表示又发送了一次验证码
        long c = Redis.执行命令:incr key;

        if (c > 5) {
            // 如果超过了一分钟内的 5 次发送限制,限制发送,返回 null
            return null;
        }
    }

    // 生成随机的 6 位数验证码
    String validationCode = 生成随机的 6 位数的验证码();

    // 设置验证码的存储键,有效期设置为 5 分钟(300 秒)
    String validationKey = "validation:" + phoneNumber;
    Redis.执行命令:set validationKey validationCode ex 300;

    // 返回生成的验证码,后续通过手机短信发送给用户
    return validationCode;
}

// 验证用户输入的验证码是否正确
boolean 验证验证码(String phoneNumber, String validationCode) {
    // 构造存储验证码的 Redis 键
    String validationKey = "validation:" + phoneNumber;

    // 从 Redis 中获取存储的验证码值
    String value = Redis.执行命令:get validationKey;

    if (value == null) {
        // 如果没有找到该手机号的验证码记录,验证失败
        return false;
    }

    // 比较用户输入的验证码是否和存储的验证码一致,返回相应的验证结果
    return value.equals(validationCode);
}

3.5 分布式锁

在 Redis 中,String 类型可以用于实现简单的分布式锁:

  • 原子性操作: Redis 的命令是原子性的,即 Redis 单个命令的执行是不可中断的,要么全部执行成功,要么全部不执行,不存在部分执行的情况。例如,SETNX 命令(设置值并仅在键不存在时设置成功)和 DEL 命令(删除键值对)都是原子操作。这种特性确保了在高并发环境下,对分布式锁的获取和释放操作是可靠的。

  • 并发控制Redis 是单线程的,通过事件循环和非阻塞 I/O 实现高并发处理。虽然 Redis 本身是单线程的,但其内部使用了时间片轮转机制来实现多个客户端的请求处理。这使得 Redis 能够高效处理大量的并发请求,适合作为分布式锁的存储和管理工具。

  • 过期时间可以为 Redis 的 String 类型设置过期时间(Expiration),即在设置键值对时可以指定键的生存时间。这一特性对于分布式锁尤为重要,可以避免因为客户端异常退出而造成的死锁情况。设置合适的过期时间可以确保即使锁未显式释放,也能在一定时间后自动释放,从而避免资源长时间被锁定。

 此功能可以⽤以下伪代码说明基本实现思路

// 示例中的参数
String lockKey = "resource_lock";
String clientId = UUID.randomUUID().toString();

// 执行 SETNX 命令
boolean lockAcquired = Redis.执行命令:setnx(lockKey, clientId);

if (lockAcquired) {
    // 如果成功获得锁
    try {
        // TODO: 执行业务逻辑
    } finally {
        // 释放锁
        Redis.执行命令:del(lockKey);
    }
} else {
    // 获取锁失败的处理逻辑
    // TODO: 处理获取锁失败的情况
}

命令说明

  • 当执行 SETNX lockKey clientId 命令时,Redis 将尝试设置键 lockKey 的值为 clientId
  • 如果 lockKey 已经存在(即已被其他客户端设置),SETNX 命令将会设置失败,返回 0
  • 如果 lockKey 不存在,SETNX 命令将设置成功,返回 1 表示获取了锁。

注意事项

  • 获取锁后,一定要确保最终释放锁,以避免锁被长时间持有而造成资源无法访问。
  • 可以结合设置过期时间的方式来实现自动释放锁,避免因客户端异常退出而导致的死锁问题。

以上介绍了使用Redis的字符串数据类型可以使用的几个场景,但其适用场景远不止于此,开发人员可以结合字符串类型的特点以及提供的命令,充分发挥自己的想象力,在自己的业务中去找到合适的场景去使用Redis的字符串类型。


码字不易,如果有用还请三连支持哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/709921.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

论文中引用网页链接的简单操作

一、参考资料 中文论文或者申请书中网页新闻引用格式 自制网页&#xff1a;在论文中快速引用网页链接 二、相关介绍 1. 常用文献类型用单字母标识 学术论文参考文献中文献类型字母标识 常用文献类型用单字母标识&#xff0c;具体如下&#xff1a; &#xff08;1&#xf…

react 0至1 案例

/*** 导航 Tab 的渲染和操作** 1. 渲染导航 Tab 和高亮* 2. 评论列表排序* 最热 > 喜欢数量降序* 最新 > 创建时间降序* 1.点击记录当前type* 2.通过记录type和当前list中的type 匹配*/ import ./App.scss import avatar from ./images/bozai.png import {useState} …

【YOLOv8改进[注意力]】在YOLOv8中添加GAM注意力 + 含全部代码和详细修改方式 + 手撕结构图

本文将进行在YOLOv8中添加GAM注意力的实践,助力YOLOv8目标检测效果的实践,文中含全部代码、详细修改方式以及手撕结构图。助您轻松理解改进的方法,实现有效涨点。 改进前和改进后的参数对比: 目录 一 GAM 二 在YOLOv8中添加GAM注意力 1 整体修改 2 配置文件

24年河北自考报名流程详细教程汇总

2024年河北自考本科报名马上就要开始了&#xff0c;想要参加考试报名的同学&#xff0c;提前看一下&#xff0c;了解一下报名流程&#xff0c;准备一些报名材料。 报名时间&#xff1a;2024年1月5日—10日8:00—22:00 考试时间&#xff1a;2024年4月13日—14日 报名照要求&…

UV胶带和UV胶水有什么区别?

UV胶带和UV胶水有什么区别&#xff1f; UV胶带和UV胶水在性质、用途、固化方式等方面存在明显的区别&#xff0c;以下是对两者区别的详细阐述&#xff1a; 性质&#xff1a; UV胶带&#xff1a;一种特殊的胶带&#xff0c;主要通过紫外线辐射进行固化&#xff0c;具有高强度粘…

后端高频面试题分享-用Java判断一个列表是否是另一个列表的顺序子集

问题描述 编写一个函数&#xff0c;该函数接受两个列表作为参数&#xff0c;判断第一个列表是否是第二个列表的顺序子集&#xff0c;返回True或False。 要求 判断一个列表是否是另一个列表的顺序子集&#xff0c;即第一个列表的所有元素在第二个列表需要顺序出现。列表中的元…

Linux iptables详解

前言&#xff1a;事情是这样的。最近部门在进行故障演练&#xff0c;攻方同学利用iptables制造了一个故障。演练最终肯定是取得了理想的效果&#xff0c;即业务同学在规定时间内定位了问题并恢复了业务(ps&#xff1a;你懂得)。 对我个人来讲一直知道iptables的存在&#xff0…

winform 应用程序 添加 wpf控件后影响窗体DPI改变

第一步&#xff1a;添加 应用程序清单文件 app.manifest 第二步&#xff1a;把这段配置 注释放开&#xff0c;第一个配置true 改成false

厂里资讯之总体架构介绍以及环境搭建

本项目是本人根据黑马程序员的微服务项目黑马头条进行包装改造&#xff0c;作为实习简历上面的项目&#xff0c;为了进一步熟悉深挖这个项目&#xff0c;写了这一系列的博客来加深自己对项目的理解。 概述 项目背景 本项目主要着手于使用户获取学校最新最热的资讯&#xff0c…

HTC-Net

表1 复现结果–Dice&#xff1a;0.8995476149550329&#xff0c;mIOU&#xff1a;0.8395136164423699&#xff0c;Recall&#xff1a;0.8688330349167194&#xff0c;F1-score&#xff1a;0.8573282647143806&#xff0c;PA&#xff1a;0.9356796542306741 与原文结果差不多 表…

OpenCV练习(1)签名修复

1.目的 在学校的学习过程中&#xff0c;需要递交许多材料&#xff0c;且每份材料上都需要对应负责人签名&#xff0c;有时候找别人要签名&#xff0c;然后自己粘贴的话&#xff0c;会出现签名模糊&#xff0c;背景不是纯白透明。为此以word中的“颜色校正”功能为参照&#xf…

图片怎么在线转换格式?电脑快速改图片格式的技巧

图片怎么把格式在线转换&#xff1f;在使用图片的时候不同平台会需要添加不同的图片格式&#xff0c;当图片格式不对时就需要使用图片格式转换器来修改当前图片的格式之后才可以正常使用。那么怎么操作能够简单快捷的修改当前图片的格式呢&#xff1f; 图片转格式可以使用网上…

java:spring【AnnotationMetadata】的简单使用例子

# 项目代码资源&#xff1a; 可能还在审核中&#xff0c;请等待。。。 https://download.csdn.net/download/chenhz2284/89435385 # 项目代码 【pom.xml】 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-start…

R 文件优化插件:Binary XML file in layout Error inflating class

场景一&#xff1a;构造函数缺失 问题 自定义布局&#xff08;FlagmentLayout&#xff09;加载自定义属性失败&#xff0c;导致广告显示异常&#xff0c;甚至是闪退&#xff5e; InflateException 在 Android 中我们遇到的通常发生在自定义 View 创建中&#xff0c;动态加载…

家用RJ45水晶头可以用在工业互联网中?

工业互联网作为智能制造的核心组成部分&#xff0c;已经在工业领域快速发展。在建立连接不同设备和系统的复杂网络中&#xff0c;网络设备和连接器的选择变得至关重要。其中&#xff0c;普遍使用的RJ45水晶头和网线在家庭和小型商业网络中被广泛采用&#xff0c;但是否适用于工…

记录一下PHP使用微信小程序支付

记录一下PHP使用微信小程序支付V3版本经历 官方文档&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_0.shtml 请详细查看文档中小程序支付接入前准备&#xff08;https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml&#xff…

电脑怎么录制游戏视频?轻松捕捉每一帧精彩

随着游戏产业的蓬勃发展&#xff0c;越来越多的玩家不仅满足于在游戏世界中的探索与冒险&#xff0c;更希望将自己的游戏精彩瞬间记录下来&#xff0c;分享给更多的朋友。可是电脑怎么录制游戏视频呢&#xff1f;本文旨在为广大游戏爱好者提供一份详细的电脑游戏视频录制攻略&a…

GraphQL(9):Spring Boot集成Graphql简单实例

1 安装插件 我这边使用的是IDEA&#xff0c;需要先按照Graphql插件&#xff0c;步骤如下&#xff1a; &#xff08;1&#xff09;打开插件管理 在IDEA中&#xff0c;打开主菜单&#xff0c;选择 "File" -> "Settings" (或者使用快捷键 Ctrl Alt S …

2024黄河流域比赛的复现

目录 WEB [GKCTF 2021]easynode unser 知识点 WEB 根据此题先复现[GKCTF 2021]easynode这个题&#xff0c;这两个题类似 [GKCTF 2021]easynode 1.打开页面发现是登录页面&#xff0c;找到源文件里面的代码&#xff0c;分析如何进行登录&#xff0c;发现经过safeQuery()函…

外网访问公司内网服务器?

【天联】组网天联可以解决不同地区电脑与电脑、设备与设备、电脑与设备之间的信息远程通信问题。在全国各主要节点部署加速服务器&#xff0c;实现在低带宽、跨运营商的网络环境下高速访问&#xff1b;这为公司内网服务器提供了一个可行的外网访问解决方案。 在现代办公环境中…