Redis 7.x 系列【6】数据类型之字符串(String)
有道无术,术尚可求,有术无道,止于术。
本系列Redis 版本 7.2.5
源码地址:https://gitee.com/pearl-organization/study-redis-demo
文章目录
- 1. 前言
- 2. 常用命令
- 2.1 SET
- 2.2 GET
- 2.3 MSET
- 2.4 MGET
- 2.5 GETSET
- 2.6 STRLEN
- 2.7 SETEX
- 2.8 SETNX
- 2.9 INCR
- 2.10 DECR
- 3. SDS(简单动态字符串)
- 3.1 二进制安全
- 3.2 查询字符串长度效率高
- 3.3 缓冲区溢出保护
- 3.4 空间预分配
- 3.5 惰性空间释放
- 4. 应用场景
- 4.1 存储常规数据
- 4.2 计数器
- 4.3 分布式锁
1. 前言
在官方文档中,可以看到 Redis 支持很多种数据类型,以解决不同场景下的各种问题。接下来,会详细介绍 Redis 中的各种数据类型, 主要是介绍一些常用的,包括:
StringListHashSetSorted set(ZSet)BitmapHyperLogLogGeospatialStream
String字符串是编程语言里最常用的数据类型,使用双引号表示。
比如JAVA:
String str="1234";
比如C语言:
char str[] = "1234";
在 Redis 中, String 类型是最基本的数据类型,是二进制安全的,可以存储任意类型的数据,文本、数字、图片或者序列化的对象 。

注意:Key的类型只能为字符串,Value的类型为字符串时,默认情况下的最大值是 512M 。
2. 常用命令
String 相关的所有命令:
| 命名 | 描述 |
|---|---|
| APPEND | 将 value 追加到 key 原来的值的末尾 |
| DECR | 将 key 中储存的数字值减一 |
| DECRBY | 将 key 所储存的值减去给定的减量值 ( decrement ) |
| GET | 设置指定 key 的值 |
| GETDEL | 获取 key 的值并删除该 key |
| GETEX | 获取 key 的值,并可选择设置其过期时间 |
| GETRANGE | 返回 key 中字符串值的子字符 |
| GETSET | 将给定 key 的值设为 value ,并返回 key 的旧值 |
| INCR | 将 key 中储存的数字值增一 |
| INCRBY | 将 key 所储存的值加上给定的增量值 ( increment ) |
| INCRBYFLOAT | 将 key 所储存的值加上给定的浮点增量值 ( increment ) |
| LCS | 实现了最长公共子序列算法,可用于评估字符串的相似程度 |
| MGET | 获取所有(一个或多个)给定 key 的值 |
| MSET | 同时设置一个或多个 key-value 对 |
| MSETNX | 同时设置一个或多个 key-value 对 |
| PSETEX | 以毫秒为单位设置 key 的生存时间 |
| SET | 设置指定 key 的值 |
| SETEX | 设置 key 的值为 value 同时将过期时间设为 seconds |
| SETNX | 只有在 key 不存在时设置 key 的值 |
| SETRANGE | 从偏移量 offset 开始用 value 覆写给定 key 所储存的字符串值 |
| STRLEN | 返回 key 所储存的字符串值的长度 |
| SUBSTR | 返回字符串值的子字符串,由偏移量开始和结束(两者都包含在内)决定 |
2.1 SET
用于给指定的 Key 设置字符串值,如果 Key 已经保存了一个值,那么这个操作会直接覆盖原来的值,并且忽略原始类型。当 SET 命令执行成功后,之前设置的过期时间都将失效。
示例:
127.0.0.1:6379> SET mykey "Hello World"
OK
127.0.0.1:6379> SET mykey "Hello World" EX 60
OK
2.2 GET
用于获取指定 Key 的字符串值,如果 Key 不存在, 那么返回特殊值 nil, 如果键 Key的值不是字符串类型, 返回错误, 因为 GET 命令只能用于字符串值。
示例:
127.0.0.1:6379> GET mykey
"Hello World"
127.0.0.1:6379> GET mykey_nil
(nil)
2.3 MSET
和 SET 命令一样,会用新值替换旧值, MSET 是原子操作,所有 Key 的值同时设置,客户端不会看到有些 Key 值被修改,而另一些 Key 值没变。总是返回 OK ,因为 MSET 不会失败。
基本语法:
MSET key1 value1 key2 value2 .. keyN valueN
示例:
127.0.0.1:6379> MSET key1 "Hello" key2 "World"
OK
127.0.0.1:6379> GET key1
"Hello"
127.0.0.1:6379> GET key2
"World"
2.4 MGET
用于获取所有给定 Key 的值,返回一个列表,值的类型是字符串,如果某个 Key 不存在或者值不是字符串,那么这个 Key 返回特殊值 nil 。
基本语法:
MGET KEY1 KEY2 .. KEYN
示例:
127.0.0.1:6379> MGET key1 key2 nonexisting
1) "Hello"
2) "World"
3) (nil)
2.5 GETSET
用于给指定的 Key 设置字符串值, 并返回设置之前的旧值。如果 Key 没有旧值返回 nil,如果 Key 对应的值存在但不是字符串类型时,返回一个错误。
示例:
127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> GETSET mykey "World"
"Hello"
127.0.0.1:6379> GET mykey
"World"
2.6 STRLEN
用于获取指定 Key 所储存的字符串值的长度,当储存的不是字符串类型时,返回错误。
基本语法:
STRLEN KEY_NAME
示例:
127.0.0.1:6379> SET mykey "Hello world"
OK
127.0.0.1:6379> STRLEN mykey
(integer) 11
127.0.0.1:6379> STRLEN mykey_nil
(integer) 0
2.7 SETEX
用于给指定的 Key 设置字符串值,并将 Key 的生存时间设置为多少秒。如果键 Key 已经存在,将覆盖已有的值。
基本语法:
SETEX key seconds value
示例:
127.0.0.1:6379> SETEX mykey 60 "Hello"
OK
127.0.0.1:6379> TTL mykey
(integer) 52
127.0.0.1:6379> GET mykey
"Hello"
2.8 SETNX
SETNX 是 SET if Not eXists 的缩写,在指定的 Key 不存在时,设置指定的值,这种情况下等同 SET 命令,当 Key 存在时,什么也不做。
返回值为整数:
1:Key存在0:Key不存在
SETNX 命令是原子性的,常用于实现分布式锁,添加成功表示获取到锁,添加失败表示未获取到锁(后续详解介绍)。
示例:
redis> SETNX mykey "Hello"
(integer) 1
redis> SETNX mykey "World"
(integer) 0
redis> GET mykey
"Hello"
2.9 INCR
用于将指定的 Key 储存的数字值增一,如果 Key 不存在,那么值会先被初始化为 0 ,然后再执行 INCR 操作,返回值为执行操作之后 Key 的值。如果值包含错误的类型,或字符串类型的值不能表示为数字,将会返回一个错误 ERR ERR hash value is not an integer。
操作的值限制在 64 位(bit)有符号数字表示之内。本质上这是一个字符串操作,因为 Redis 没有专门的整数类型,储在 Key 中的字符串被转换为十进制有符号整数,在此基础上加 1 。常用于计数器、限流(后续详解介绍)。
基本语法:
INCR KEY_NAME
示例:
127.0.0.1:6379> SET mykey "10"
"OK"
127.0.0.1:6379> INCR mykey
(integer) 11
127.0.0.1:6379> GET mykey
"11"
2.10 DECR
用于将指定的 Key 储存的数字值减去一,如果 Key 不存在,那么值会先被初始化为 0 ,然后再执行 DECR 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,将会返回一个错误。操作的值限制在 64 位(bit)有符号数字表示之内,返回值为执行操作之后 Key 的值
基本语法:
DECR KEY_NAME
示例:
127.0.0.1:6379> DECR mykey
(integer) 9
127.0.0.1:6379> SET mykey "234293482390480948029348230948"
"OK"
127.0.0.1:6379>DECR mykey
ERR ERR value is not an integer or out of range
3. SDS(简单动态字符串)
SDS 是 Simple Dynamic String 的首字母缩写,翻译为简单的动态字符串,是 Redis 自定义的一种表示字符串的特殊数据结构。相较于传统的C语言字符串,SDS 具有更多的功能和更高的性能,当前也会占用更多的内存。
Redis 3.2 之前的版本:
struct sdshdr {int len; // 记录buf数组中已使用字节的数量,即字符串的实际长度int free; // 存储剩余(空闲)的空间char buf[]; // 存储实际数据
};
Redis 3.2 之后的版本,SDS 变成了 5 种数据结构,不同类型的存储空间大小不一样:
/* Note: sdshdr5 is never used, we just access the flags byte directly.* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {unsigned char flags; /* 3 lsb of type, and 5 msb of string length */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; // 已用空间的长度,占 4 个字节,不包括 ‘\0’;uint8_t alloc; // 实际分配长度,占 4 个字节,不包括 ‘\0’;unsigned char flags; // 标记当前 buf[] 类型( sdshdr8/16/32/64)char buf[]; // 存储实际数据
};
struct __attribute__ ((__packed__)) sdshdr16 {uint16_t len; /* used */uint16_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {uint32_t len; /* used */uint32_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {uint64_t len; /* used */uint64_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
相比于C语言字符串,SDS 有以下优点:
- 二进制安全
- 查询字符串长度效率高
- 缓冲区溢出保护
- 空间预分配
- 惰性空间释放
3.1 二进制安全
在 C 语言中,用字符 \0 表示字符串的结束,如果字符串中本身就有 \0 字符,字符串就会被截断,即非二进制安全,例如 hello \0 world 会被截断解析为 hello。
SDS 不受 \0 字符影响,能够准确存储任意二进制数据,因为它基于 len 属性而非遇到 \0 来判断字符串的结束位置。
3.2 查询字符串长度效率高
在 C 语言中,获取一个字符串长度时,需对整个字符串进行遍历,直至遇到结束符号。在高并发场景下频繁遍历字符串,势必会造成性能瓶颈。
SDS 中于 len 属性记录了字符串的长度,可以直接通过 STRLEN 命令获取长度即可。
3.3 缓冲区溢出保护
在 C 语言中,字符串本身不记录可用空间大小,在进行字符串拼接等操作时,如果没有检查就可能会导致缓冲区溢出。
SDS 中于 free 属性记录了额外未使用的空间大小,每次进行字符串操作前都会检查剩余空间是否足够,不足时会自动扩容,有效避免了缓冲区溢出问题。
3.4 空间预分配
在 C 语言中,每次修改字符串长度(增加或减少)时,通常需要重新分配内存,这可能导致频繁的内存操作。
SDS 优化了字符串增长操作,当修改字符串并需对 SDS 的空间进行扩展时,不仅会为 SDS分配修改所必要的空间,还会分配额外的未使用空间(free属性),下次再修改就先检查未使用空间free是否满足,满足则不用在扩展空间。有效的减少字符串连续增长操作,减少所产生的内存重分配次数。
3.5 惰性空间释放
惰性空间释放策略则用于优化 SDS 字符串缩短操作,当缩短 SDS 字符串后,并不会立即执行内存重分配来回收多余的空间,而是用 free 属性将这些空间记录下来,如果后续有增长操作,则可直接使用。
4. 应用场景
4.1 存储常规数据
String 可以存储任意类型的数据,文本、数字、图片或者序列化的对象 。
常用实际场景:
- 图形、短信验证码
- 令牌
例如,存储短信验证码并设置过期时间为 60 秒:
localhost:0>SET 13688889999 80906 EX 60
"OK"
localhost:0>GET 13688889999
"80906"
4.2 计数器
INCR 用于将指定的 Key 储存的数字值增一, DECR 用于将指定的 Key 储存的数字值减去一。
常用实际场景:
- 阅读数
- 点赞
- 分布式
ID - 网站访问量
- 记录接口访问次数,实现防止重复提交、简单限流
例如,使用 INCR 记录网站每日访问量:
localhost:0>SET web_views:20240617 0
"OK"
localhost:0>INCR web_views:20240617
"1"
localhost:0>GET web_views:20240617
"1"
4.3 分布式锁
SETNX 命令是原子性的,常用于实现分布式锁,添加成功表示获取到锁,添加失败表示未获取到锁(后续详解介绍)。
例如,执行 SETNX 添加锁,返回 1 表示成功获取到锁:
localhost:0>SETNX my_lock yes
"1"
其他线程执行SETNX,返回 0 表示获取锁失败:
localhost:0>SETNX my_lock yes
"0"
执行完成后,删除锁,其他线程再次获取则成功:
localhost:0>DEL my_lock
"1"
localhost:0>SETNX my_lock yes
"1"
相关文章:
Redis 7.x 系列【6】数据类型之字符串(String)
有道无术,术尚可求,有术无道,止于术。 本系列Redis 版本 7.2.5 源码地址:https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 前言2. 常用命令2.1 SET2.2 GET2.3 MSET2.4 MGET2.5 GETSET2.6 STRLEN2.7 SETEX2.8…...
指针(一)
指针基础 在C中,指针是至关重要的组成部分。它是C语言最强大的功能之一,也是最棘手的功能之一。 指针具有强大的能力,其本质是协助程序员完成内存的直接操纵。 指针:特定类型数据在内存中的存储地址,即内存地址。 …...
harmony鸿蒙下实现bc交互的方式和方法
前言 最近在研究harmony操作系统下的交互,因此写一篇文章记录一下。 解决的问题 本篇文章主要是来写解决如果兼容android或者ios的交互,这样子避免h5页面的二次开发,节省资源。 交互的种类 交互对于harmony来说其实只有一种,…...
【MySQL进阶之路 | 高级篇】索引的声明与使用
1. 索引的分类 MySQL的索引包括普通索引,唯一性索引,全文索引,单列索引和空间索引. 从功能逻辑上说,索引主要分为普通索引,唯一索引,主键索引和全文索引.按物理实现方式,索引可以分为聚簇索引…...
探索Java中的设计模式:从单例到工厂模式
探索Java中的设计模式:从单例到工厂模式 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨Java中的设计模式,从经典的单…...
表单(forms)
自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在app1文件夹下创建一个forms.py文件,添加如下类代码: from django import forms class PersonForm(forms.Form): first_na…...
Geoserver源码解读四 REST服务
文章目录 文章目录 一、概要 二、前置知识点-FreeMarker 三、前置知识点-AbstractHttpMessageConverter 3.1 描述 3.2 应用 四、前置知识点-AbstractDecorator 4.1描述 4.2 应用 五、工作空间查询解读 5.1 模板解读 5.2 请求转换器解读 一、概要 关于geoserver的r…...
硬件开发笔记(二十一):外部搜索不到的元器件封装可尝试使用AD21软件的“ManufacturerPart Search”功能
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/139869584 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...
【AI大模型】GPTS 与 Assistants API
前言 2023 年 11 月 6 日,OpenAI DevDay 发表了一系列新能力,其中包括:GPT Store 和 Assistants API。 GPTs 和 Assistants API 本质是降低开发门槛 可操控性和易用性之间的权衡与折中: 更多技术路线选择:原生 API、…...
攻击者开始使用 XLL 文件进行攻击
近期,研究人员发现使用恶意 Microsoft Excel 加载项(XLL)文件发起攻击的行动有所增加,这项技术的 MITRE ATT&CK 技术项编号为 T1137.006。 这些加载项都是为了使用户能够利用高性能函数,为 Excel 工作表提供 API …...
Why RAG is slower than LLM?
I used RAG with LLAMA3 for AI bot. I find RAG with chromadb is much slower than call LLM itself. Following the test result, with just one simple web page about 1000 words, it takes more than 2 seconds for retrieving: 我使用RAG(可能是指某种特定的…...
Word页码设置,封面无页码,目录摘要阿拉伯数字I,II,III页码,正文开始123为页码
一、背景 使用Word写项目书或论文时,需要正确插入页码,比如封面无页码,目录摘要阿拉伯数字I,II,III为页码,正文开始以123为页码,下面介绍具体实施方法。 所用Word版本:2021 二、W…...
汽车汽配图纸管理、产品研发管理解决方案
汽车汽配图纸管理、产品研发管理解决方案 随着全球汽车市场的快速发展,中国汽车汽配行业迎来了前所未有的发展机遇。然而,在这一过程中,企业也面临着诸多挑战,如研发能力的提升、技术资料管理的复杂性、以及跨部门协作的困难等。为…...
小程序简单版音乐播放器
小程序简单版音乐播放器 结构 先来看看页面结构 <!-- wxml --><!-- 标签页标题 --> <view class"tab"><view class"tab-item {{tab0?active:}}" bindtap"changeItem" data-item"0">音乐推荐</view><…...
驾校预约管理系统
摘 要 随着驾驶技术的普及和交通安全意识的增强,越来越多的人选择参加驾校培训,以获取驾驶执照。然而,驾校管理面临着日益增长的学员数量和繁琐的预约管理工作。为了提高驾校的管理效率和服务质量,驾校预约管理系统成为了必不可少…...
C++ 左值右值 || std::move() || 浅拷贝,深拷贝 || 数据类型
数据类型: 作用:决定变量所占内存空间的字节大小,和布局方式基本数据类型: 算数类型: 整形(bool / char……扩展集 / int / long……)&& 浮点形(float/double……ÿ…...
发那科机器人IO 分配
IO 信号 也称为输入\输出信号,是机器人与外围设备通信的电信号...
ubuntu开机怎么进入、退出命令行界面
要在Ubuntu系统开机时进入命令行界面,可以按照以下步骤操作: 在开机过程中按下Ctrl Alt F1组合键,这将会切换到第一个虚拟控制台,即命令行界面。如果Ctrl Alt F1没有生效,也可以尝试Ctrl Alt F2、Ctrl Alt F3…...
『FPGA通信接口』LVDS接口(4)LVDS接收端设计
文章目录 1.LVDS接收端概述2逻辑框图3.xapp855训练代码解读4.接收端发送端联调5.传送门 1.LVDS接收端概述 接收端的传输模型各个属性应该与LVDS发送端各属性一致,例如,如果用于接收CMOS图像传感器的图像数据,则接收端程序的串化因子、通道个…...
面试题:HTTP的body是二进制还是文本
实际上,HTTP的body可以是二进制数据,也可以是文本。HTTP协议本身不对body内容的格式做限制,具体格式取决于Content-Type头字段的定义。 文本数据: 当Content-Type头字段指定为文本类型时(如text/plain、text/html、ap…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
