当前位置: 首页 > news >正文

redis 中的 String 数据结构

简介

String类型在 redis 中最常见的数据类型,是二进制安全的,可以存放字符串、数值、json、图像数据,value最大数据量是 512M

二进制安全:Redis 的 string 类型是二进制安全的。所谓二进制安全,是指无论输入的数据是什么字节序列,Redis 都能准确无误地存储和返回,不会因为数据中可能包含特殊字符、编码格式等问题而对数据进行错误处理。 主要原因是SDS 的存储不像 C 字符串那样以 ' \0 ' 作为字符串结束的标识。

常用命令

set < key>< value>:添加键值对
nx:当数据库中key不存在时,可以将key-value添加到数据库
xx: 当数据库key存在时,可以将key-value添加到数据库,与nx参数互斥
ex: 设置key-value添加到数据库,并设置key的超时时间(以秒钟为单位)
px:设置key-value添加到数据库,并设置key的超时时间(以豪秒钟为单位),与ex互斥
get < key>查询对应键值
append < key>< value>:将给定的值追加到key的末尾
strlen < key>:获取值的长度
setnx < key>< value>:只有在key不存在时,设置key-value加入到数据库
setex < key> < timeout>< value>:添加键值对,同时设置过期时间(以秒为单位)
incr < key>:将key中存储的数字加1处理,只能对数字值操作。如果是空,值为1
decr < key>:将key中存储的数字减1处理,只能对数字值操作。如果是空,值为1
incrby < key>< increment>:将key中存储的数字值增加指定步长的数值,如果是空,值为步长。
(具有原子性)
decrby < key>< decrement>: 将key中存储的数字值减少指定步长的数值,如果是空,值为步长。
(具有原子性)
mset < key1>< value1>[< key2>< value2>...]:同时设置1个或多个key-value值
mget < key1>[< key2>...]:同时获取1个或多个value
msetnx < key1>< value1>[< key2>< value2>...]:当所有给定的key都不存在时,同时设置1个或
多个key-value值(具有原子性)
getrange/substr < key>< start>< end> 将给定key,获取从start(包含)到end(包含)的值
setrange < key>< offset>< value>:从偏移量offset开始,用value去覆盖key中存储的字符串值
getset< key>< value>: 对给定的key设置新值,同时返回旧值。如果key不存在,则添加一个
key-value值

SDS

struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len;      // 已使用的字节数uint8_t alloc;    // 分配的总字节数(包含'\0')char buf[];       // 柔性数组,存放实际的字符串内容
};
  • len:记录了当前字符串的长度,这样获取字符串长度的操作时间复杂度为 O(1),而 C 字符串获取长度需要遍历到 '\0',时间复杂度为 O(N)
  • alloc:表示分配给 buf 数组的总字节数(包括字符串结束符 '\0' 占用的 1 个字节),这有助于内存管理,在需要扩展字符串时,可以预先判断是否有足够空间,减少频繁的内存重新分配。
  • buf:是一个柔性数组,用于存放实际的字符串内容,并且总是以 '\0' 结尾,这样可以兼容部分 C 字符串函数。

SDS的内存分配与管理

  • 空间预分配:当 SDS 进行扩展操作时,如果扩展后长度小于 1MB,Redis 会分配两倍于所需大小的空间。例如,若原 SDS 长度为 10 字节,扩展后需 20 字节,那么实际会分配 40 字节的空间。如果扩展后长度大于等于 1MB,会额外分配 1MB 的空间。这样做可以减少频繁的内存重新分配操作,提升性能。
  • 惰性空间释放:当 SDS 缩短时,Redis 并不会立即释放多余的空间,而是将这些空间保留在 SDS 中,等待后续可能的扩展操作。例如,从一个长度为 100 的 SDS 中删除部分内容使其长度变为 50,此时不会释放剩余 50 字节的空间,而是将 alloc 调整为 100,len 调整为 50,下次有扩展需求时可直接使用这些空间。

SDS与 c 字符串的区别及优势

  • 获取长度效率:如前所述,C 字符串获取长度需遍历到 '\0',时间复杂度为 O(N),而 SDS 通过 len 字段直接获取,时间复杂度为 O(1)。在频繁获取字符串长度的场景下,SDS 性能更优。
  • 缓冲区溢出:C 字符串在进行拼接等操作时,如果没有预先分配足够空间,很容易导致缓冲区溢出。而 SDS 在进行修改操作时,会先检查空间是否足够,若不足则会进行空间扩展,从而避免缓冲区溢出问题。
  • 内存分配次数:由于 SDS 的空间预分配和惰性空间释放策略,相较于 C 字符串频繁的内存分配和释放,SDS 能显著减少内存分配次数,提升性能并降低内存碎片产生的概率。

应用场景

单值缓存 set key value

get key

对象缓存

set stu:001 value(json)

mset stu:001:name zhangsan stu:001:age 18 stu:001:gender 男

mget stu:001:name stu:001:age

分布式锁

setnx key:001 true //返回1代表加锁成功

setnx key:001 true //返回0代表加锁失败

//.....业务操作

del key:001 //执行完业务释放锁

set key:001 true ex 20 nx //防止程序意外终止导致死锁

计数器

incr article:read:1001

//统计文章阅读数量

分布式系统全局序列号

incrby orderid 100

//批量生成序列号

package com.pgs.redisstring;import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;import java.io.*;
import java.util.Base64;public class JedisStringOperations {private static final String REDIS_HOST = "localhost";private static final int REDIS_PORT = 6379;private static final String LOCK_KEY = "distributed_lock";private static final String COUNTER_KEY = "counter";private static final String SEQUENCE_KEY = "global_sequence";public static void main(String[] args) {Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT);// 单值缓存singleValueCache(jedis);// 对象缓存objectCache(jedis);// 分布式锁distributedLock(jedis);// 计数器counter(jedis);// 分布式系统全局序列号globalSequence(jedis);jedis.close();}// 单值缓存public static void singleValueCache(Jedis jedis) {String key = "single_value_key";String value = "single_value";jedis.set(key, value);System.out.println("单值缓存:" + jedis.get(key));}// 对象缓存public static void objectCache(Jedis jedis) {String key = "object_key";User user = new User("John", 30);String serializedUser = serialize(user);jedis.set(key, serializedUser);User deserializedUser = (User) deserialize(jedis.get(key));System.out.println("对象缓存 - 姓名:" + deserializedUser.getName() + ", 年龄:" + deserializedUser.getAge());}// 分布式锁public static void distributedLock(Jedis jedis) {SetParams setParams = new SetParams();setParams.nx().ex(10);String result = jedis.set(LOCK_KEY, "locked", setParams);if ("OK".equals(result)) {try {System.out.println("获取到分布式锁,执行临界区代码...");} finally {jedis.del(LOCK_KEY);System.out.println("释放分布式锁");}} else {System.out.println("未获取到分布式锁");}}// 计数器public static void counter(Jedis jedis) {long count = jedis.incr(COUNTER_KEY);System.out.println("计数器值:" + count);}// 分布式系统全局序列号public static void globalSequence(Jedis jedis) {long sequence = jedis.incr(SEQUENCE_KEY);System.out.println("分布式系统全局序列号:" + sequence);}// 序列化对象public static String serialize(Object obj) {try {ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(obj);return Base64.getEncoder().encodeToString(bos.toByteArray());} catch (IOException e) {e.printStackTrace();return null;}}// 反序列化对象public static Object deserialize(String str) {try {byte[] data = Base64.getDecoder().decode(str);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));return ois.readObject();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();return null;}}
}    

http://www.xdnf.cn/news/43849.html

相关文章:

  • 【Linux系统】Linux基础指令(详解Linux命令行常用指令,每一个指令都有示例演示)
  • 【2025计算机网络-面试常问】http和https区别是什么,http的内容有哪些,https用的是对称加密还是非对称加密,流程是怎么样的
  • 【人工智能】推荐开源企业级OCR大模型InternVL3
  • 【后端开发】MyBatis
  • 树莓派系统中设置固定 IP
  • Oracle 23ai Vector Search 系列之6 向量相似性搜索(Similarity Search)
  • 力扣DAY60-61 | 热100 | 回溯:单词搜索、分割回文串
  • 17.【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--SonarQube部署与配置
  • kotlin知识体系(六) : Flow核心概念与与操作符指南
  • opencv图像库编程
  • 软件开发过程中技术债的控制策略
  • iPhone 13P 换超容电池,一年实记的“电池循环次数-容量“柱状图
  • next.js 如何实现动态路由?
  • 【消息队列RocketMQ】一、RocketMQ入门核心概念与架构解析
  • Git拉分支技巧:从零开始创建并推送分支
  • 每天学一个 Linux 命令(28):ln
  • 产品经理学习过程
  • 深度剖析即梦 AI:开启创意无限的智能创作时代
  • springboot--web开发响应参数注解
  • Web前端:百度首页克隆 - 前端开发练习
  • 网络设备基础运维全攻略:华为/思科核心操作与巡检指南
  • 2.2 BackgroundWorker的使用介绍
  • Python实现对大批量Word文档进行批量自动化排版(15)
  • 数字系统与编码
  • 2020 年 7 月大学英语四级考试真题(组合卷)——解析版
  • 并发设计模式实战系列(4):线程池
  • RabbitMQ和Seata冲突吗?Seata与Spring中的事务管理冲突吗
  • Chromium 134 编译指南 Ubuntu篇:环境搭建与源码获取(一)
  • PyTorch基础笔记
  • python爬虫复习