五大常见的数据类型之 String

article/2025/7/30 20:45:23

前言

我们都知道 Redis 提供了丰富的数据类型,常见的有五种:String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)

今天我们就来详细的聊聊 Redis 这五大常见的数据类型之一 String

结构类型结构存储的值结构读写能力
String可以是字符串,整数以及浮点数;对整个字符串或字符串的一部分进行操作;
对整数或者浮点数进行自增或者自减操作;

应用场景:缓存对象、常规计数、分布式锁、共享 session 信息等。

概述简介

String 是最基本的 key-value 结构,key 是唯一标识,value 是具体的值,value其实不仅是字符串, 也可以是数字(整数或浮点数),value 最多可以容纳的数据长度是 512M

内部实现

String 类型的底层的数据结构实现主要是 int 和 SDS(简单动态字符串)。

SDS 和我们认识的 C 字符串不太一样,之所以没有使用 C 语言的字符串表示,因为 SDS 相比于 C 的原生字符串:

  • SDS 不仅可以保存文本数据,还可以保存二进制数据。因为 SDS 使用 len 属性的值而不是空字符来判断字符串是否结束,并且 SDS 的所有 API 都会以处理二进制的方式来处理 SDS 存放在 buf[] 数组里的数据。所以 SDS 不光能存放文本数据,而且能保存图片、音频、视频、压缩文件这样的二进制数据。
  • SDS 获取字符串长度的时间复杂度是 O(1) 。因为 C 语言的字符串并不记录自身长度,所以获取长度的复杂度为 O(n);而 SDS 结构里用 len 属性记录了字符串长度,所以复杂度为 O(1)
  • Redis 的 SDS API 是安全的,拼接字符串不会造成缓冲区溢出。因为 SDS 在拼接字符串之前会检查 SDS 空间是否满足要求,如果空间不够会自动扩容,所以不会导致缓冲区溢出的问题。

字符串对象的内部编码(encoding)有 3 种 :intrawembstr

如果一个字符串对象保存的是整数值,并且这个整数值可以用 long 类型来表示,那么字符串对象会将整数值保存在字符串对象结构的 ptr 属性里面(将 void* 转换成 long),并将字符串对象的编码设置为 int

如果字符串对象保存的是一个字符串,并且这个字符串的长度小于等于 32 字节(redis 2.+ 版本),那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串,并将对象的编码设置为 embstr, embstr 编码是专门用于保存短字符串的一种优化编码方式:

如果字符串对象保存的是一个字符串,并且这个字符串的长度大于 32 字节(redis 2.+ 版本),那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串,并将对象的编码设置为 raw

注意,embstr 编码和 raw 编码的边界在 redis 不同版本中是不一样的:

  • redis 2.+ 是 32 字节;
  • redis 3.0-4.0 是 39 字节;
  • redis 5.0 是 44 字节;

可以看到 embstrraw 编码都会使用 SDS 来保存值,但不同之处在于 embstr 会通过一次内存分配函数来分配一块连续的内存空间来保存 redisObjectSDS,而 raw 编码会通过调用两次内存分配函数来分别分配两块空间来保存 redisObjectSDS。Redis这样做会有很多好处:

  • embstr 编码将创建字符串对象所需的内存分配次数从 raw 编码的两次降低为一次;
  • 释放 embstr 编码的字符串对象同样只需要调用一次内存释放函数;
  • 因为 embstr 编码的字符串对象的所有数据都保存在一块连续的内存里面可以更好的利用 CPU 缓存提升性能。

但是 embstr 也有缺点的:

  • 如果字符串的长度增加需要重新分配内存时,整个 redisObject 和 sds 都需要重新分配空间,所以 embstr 编码的字符串对象实际上是只读的,redis 没有为 embstr 编码的字符串对象编写任何相应的修改程序。当我们对 embstr 编码的字符串对象执行任何修改命令(例如 append)时,程序会先将对象的编码从 embstr 转换成 raw,然后再执行修改命令。

常用指令

基本操作:

# 设置 key-value 类型的值
127.0.0.1:6379> SET name sid10t
OK# 根据 key 获得对应的 value
127.0.0.1:6379> GET name
"sid10t"# 判断某个 key 是否存在
127.0.0.1:6379> EXISTS name
(integer) 1# 返回 key 所储存的字符串值的长度
127.0.0.1:6379> STRLEN name
(integer) 6# 删除某个 key 对应的值
127.0.0.1:6379> DEL name
(integer) 1

批量操作:

# 批量设置 key-value 类型的值
# mset key value [key value ...]
127.0.0.1:6379> MSET name sid10t age 18
OK# 批量获取多个 key 对应的 value
# mget key [key ...]
127.0.0.1:6379> MGET name age
1) "sid10t"
2) "18"

计数器(字符串的内容为整数的时候可以使用):

# 设置 key-value 类型的值
127.0.0.1:6379> SET cnt 0
OK# 将 key 中储存的数字值 +1
127.0.0.1:6379> INCR cnt
(integer) 1# 将 key 中存储的数字值 +10
# incrby key increment
127.0.0.1:6379> INCRBY cnt 10
(integer) 11# 将 key 中储存的数字值 -1
127.0.0.1:6379> DECR cnt
(integer) 10# 将 key 中存储的数字值 -6
# decrby key decrement
127.0.0.1:6379> DECRBY cnt 6
(integer) 4

过期(默认为永不过期):

# 设置 key 在 30 秒后过期(该方法是针对已经存在的key设置过期时间)
# expire key seconds [NX|XX|GT|LT]
127.0.0.1:6379> EXPIRE name 30
(integer) 1# 查看数据还有多久过期
127.0.0.1:6379> TTL name
(integer) 20# 设置 key-value 类型的值,并设置该 key 的过期时间为 20 秒
# set key value [NX|XX] [GET] [EX seconds|PX milliseconds|EXAT uni
127.0.0.1:6379> SET name sid10t EX 20
OK
# setex key seconds value
127.0.0.1:6379> SETEX name 20 sid10t
OK

不存在就插入:

# 不存在就插入(not exists)
# setnx key value
127.0.0.1:6379> SETNX name sid10t
(integer) 1

应用场景

缓存对象

使用 String 来缓存对象有两种方式:

  • 直接缓存整个对象的 JSON: SET user:1 '{"name":"sid10t", "age":18}'
  • 采用将 key 进行分离为 user:ID:property,采用 MSET 存储,用 MGET 获取各属性值: MSET user:1:name sid10t user:1:age 18 user:2:name sidiot user:2:age 20

常规计数

因为 Redis 处理命令是单线程,所以执行命令的过程是原子的。因此 String 数据类型适合计数场景,比如计算访问次数、点赞、转发、库存数量等等。

比如计算文章的阅读量:

# 初始化文章的阅读量
127.0.0.1:6379[3]> SET atc:rcnt:10086 0
OK#阅读量 +1
127.0.0.1:6379[3]> INCR atc:rcnt:10086
(integer) 1#阅读量 +1
127.0.0.1:6379[3]> INCR atc:rcnt:10086
(integer) 2# 获取对应文章的阅读量
127.0.0.1:6379[3]> GET atc:rcnt:10086
"2"

分布式锁

SET 命令有个 NX 参数可以实现「key 不存在才插入」,可以用它来实现分布式锁:

  • 如果 key 不存在,则显示插入成功,可以用来表示加锁成功;
  • 如果 key 存在,则会显示插入失败,可以用来表示加锁失败。

一般而言,还会对分布式锁加上过期时间,分布式锁的命令如下:

127.0.0.1:6379[3]> SET lock uuid NX PX 10000
OK
  • lock 就是 key 键;
  • uuid 是客户端生成的唯一的标识;
  • NX 代表只在 lock 不存在时,才对 lock 进行设置操作;
  • PX 10000 表示设置 lock 的过期时间为 10s,这是为了避免客户端发生异常而无法释放锁。

而解锁的过程就是将 lock 键删除,但不能乱删,要保证执行该操作的客户端就是加锁的客户端。所以,解锁的时候,我们要先判断锁的 uuid 是否为加锁客户端,是的话,才将 lock 键删除。

可以看到,解锁是有两个操作,这时就需要 Lua 脚本来保证解锁的原子性,因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,保证了锁释放操作的原子性。

// 释放锁时,先比较 uuid 是否相等,避免锁的误释放
if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])
elsereturn 0
end

这样一来,就通过使用 SET 命令和 Lua 脚本在 Redis 单节点上完成了分布式锁的加锁和解锁。

共享 Session 信息

通常我们在开发后台管理系统时,会使用 Session 来保存用户的会话(登录)状态,这些 Session 信息会被保存在服务器端,但这只适用于单系统应用,如果是分布式系统此模式将不再适用。

例如用户一的 Session 信息被存储在服务器一,但第二次访问时用户一被分配到服务器二,这个时候服务器并没有用户一的 Session 信息,就会出现需要重复登录的问题,问题在于分布式系统每次会把请求随机分配到不同的服务器。

分布式系统单独存储 Session 流程图:

因此,我们需要借助 Redis 对这些 Session 信息进行统一的存储和管理,这样无论请求发送到那台服务器,服务器都会去同一个 Redis 获取相关的 Session 信息,这样就解决了分布式系统下 Session 存储的问题。

分布式系统使用同一个 Redis 存储 Session 流程图:


http://chatgpt.dhexx.cn/article/RyHhcoDY.shtml

相关文章

数据库String字符串

char(n) varchar(n) tinyint tinytext text mediumtext longtextchar(0-255)varchar(0-21844) // 63533定长字符串 char()变长字符串 varchar(n) tinytext text mediumtext longtext(4GBtext)-- char varchar tinytext text mediumtext longtext -- 23767-1 21845-1 16383-1…

STRING:蛋白质相互作用(PPI网络)数据库简介

欢迎关注微信公众号《生信修炼手册》! 研究蛋白之间的相互作用网络,有助于挖掘核心的调控基因,目前已经有很多的蛋白质相互作用的数据库,而string绝对是其中覆盖的物种最多,相互作用信息做大的一个,网址如下 https://…

string数据库使用和实践第一部分string数据库介绍

背景 为什么要寻找蛋白质互做关系? 因为只有正确地发现和注释细胞中的所有功能性的相互作用关系,才能对细胞的功能进行系统层面的学习和理解。 大家在收集和展现蛋白质相互作用的信息上,一直在努力地跟上相互作用关系探索的步伐 近年来&#…

解决虚拟机桥接模式无法上网的问题

1.检查IP地址以及网关等信息是否正确 vim /etc/network/interfaces这里设置的是静态ip, auto lo iface lo inet loopback auto eth0 iface eth0 inet stastic address 192.168.43.40 # 设置IP netmask 255.255.255.0 # 设置子网掩码 gateway 192.168.43.19 # 设置网关 首先…

VM虚拟机桥接模式无法联网解决办法

1.桥接模式的意义: 桥接模式----使虚拟机客户机可以和主机在同一网段,这样,和主机同局域网内的其他主机就也可以ping到虚拟机了 2.问题描述: 1.主机和虚拟机客户机相互之间ping不通 2.将虚拟机改为网络模式为NAT模式自动获取I…

虚拟机配置桥接模式(bridge)

使用的Vmware虚拟机软件 需要使用bridge,桥接模式 首先,需要给主机电脑设置IP, 看主机使用的是有线还是无线,使用哪个就设置那个,可以先通过ipconfig/all来查看ip,然后根据实际信息配置网络适配器 手动配置…

虚拟机桥接模式下的网络设置

虚拟机共有三种网络模式,每种网络模式具体的原理参考: Vmware虚拟机三种网络模式详解 - 星朝 - 博客园原文来自http://note.youdao.com/share/web/file.html?id236896997b6ffbaa8e0d92eacd13abbf&typenote 我怕链https://www.cnblogs.com/jpfss/p/…

Virtualbox虚拟机桥接模式配置

VirtualBox提供了多种网络连接方式,不同的网络连接方式决定了虚拟机是否可以联网,以及是否可以和宿主机互相ping通 亲测之后总结一些在配置NAT模式和仅主机模式所踩的坑,最后选择了桥接模式 NAT模式:宿主机ping不通虚拟机&#…

VM虚拟机桥接模式设置固定IP

目录 一、VM虚拟机续订 二、Linux配置静态IP 一、VM虚拟机续订 选中虚拟机——>设置——>网络适配器 官方说明: 如果在笔记本电脑或其他移动设备上使用虚拟机,请选择复制物理网络连接状态。 当您在有线或无线网络之间进行移动时,该…

虚拟机桥接模式连不上网问题(非桥接网卡原因)

虚拟机和宿主机可以互相ping通,但是ping www.baidu.com不能成功 常见的原因是桥接到的网卡不对,网上搜也是大部分搜到这种原因解决办法。 参见解决VMware虚拟机桥接模式上不了网 我遇到的问题不是这个,是因为我没有配置网关。。。。。 真…

设置虚拟机桥接模式以及解决桥接模式上不了网以及ping不通主机的问题

一.VMware设置桥接模式 1.VMware -> 编辑->虚拟网络编辑器->更改设置 选择VMnet0(桥接模式),选择与主机同名网卡 ,主机可在在网络中心查看网卡名称

虚拟机桥接模式上网

记录一下嵌入式学习迈出的第一步:上网 首先选择虚拟机设置->硬件->网络适配器,选择桥接模式,下面的复制物理网络连接设置也要勾选,点确定。 在自己主机调出命令界面,输入 ipconfig /all 查看主机的上网配置&…

解决VMware虚拟机桥接模式无法上网

步骤1:查看本地以太网属性是否安装VMware Bridge Protocol 控制面板>>网络和Internet>>网络连接>>以太网右键属性>>查看是否有安装VMware Bridge Protocol 步骤2:查看VMware虚拟网络编辑器的VMnet0桥接模式设置 编辑>>虚…

VMware虚拟机桥接模式配置,设置虚拟机连接公网

1、配置时,虚拟机先关闭,双击 “网络适配器” 2、设置为 “桥接模式”,然后点击下方 “确定” 3、展开 “编辑” 菜单 点击 “虚拟网络编辑器” 进入虚拟网络编辑页面 4、点击 “更改设置” 点击更改设置,进入设置界面 5、选中 …

VMware虚拟机三种网络模式:桥接模式,NAT模式,仅主机模式

目录 一、桥接模式 二、NAT模式 三、仅主机模式 虚拟系统:CentOS 6.8 在VMware虚拟网网络编辑器中我们可以看到有三个虚拟交换机分别对应不同的网络模式: VMnet0:用于桥接模式下的虚拟交换机 VMnet1:用于仅主机模式下的虚拟交…

VMware虚拟机三种网络模式----桥接模式

vmware为我们提供了三种网络工作模式,它们分别是: Bridged(桥接模式)NAT(网络地址转换模式)Host-Only(仅主机模式) 打开vmware虚拟机,我们可以在选项栏的“编辑”下的“…

虚拟机桥接模式配置网络

虚拟机桥接模式配置网络 这个是详版,对于想了解一些相关知识的读者有些许帮助。如果想快速配置完网络,请转至简版(•‾̑⌣‾̑•)✧˖ 桥接模式就是将主机网卡与虚拟机的网卡利用虚拟网桥进行通信。在桥接的作用下,类似于把物理主机虚拟为…

虚拟机桥接模式无法联网

问题:虚拟机桥接模式无法联网 解决:1、打开虚拟网络编辑器 2、点击右下角更改设置 3、下拉选择网卡(控制面板\网络和 Internet\网络连接),并点击确定 4、打开虚拟机设置,网络连接选择自定义&#xff0c…

VMware虚拟机三种网络模式详解--Bridged(桥接模式)

VMware虚拟机三种网络模式详解--Bridged(桥接模式) 简介: 由于Linux目前很热门,越来越多的人在学习Linux,但是买一台服务器放家里来学习,实在是很浪费。 那么如何解决这个问题?虚拟机软件是很好…

VMware虚拟机配置桥接模式

虚拟机配置桥接模式 参考教程:https://blog.csdn.net/weixin_35784370/article/details/119660049 环境说明: 操作系统:Windows10 虚拟机软件:VMware 16 Pro 虚拟机:CentOS7.6 在虚拟机中以 root用户 执行操作 目的&am…