Redis值数据类型——String

4.1 string

4.1.1 概述

  1. SDS
    redis中没有使用C语言的字符串表示,而是自定义一个数据结构叫SDS(simple dynamic string)即简单动态字符串。
  2. 源码
    打开下载的redis源码包,找到src下的sds.h文件查看sds源码:


    Redis 5.0.14 的 SDS 有 5 种结构体,核心区别是 len/alloc 的字节大小;
    目的是 "按字符串长度选最小结构体",节省内存,日常用最多的是 sdshdr8(短字符串)和 sdshdr16(中等长度字符串)。

|-------|----------------|
| 字段 | 简单含义 |
| len | 字符串实际有多长 |
| alloc | 字符串最多能存多长 |
| flags | 标记这是哪种 SDS 结构体 |
| buf | 真正存字符串内容的地方 |

  1. C语言和Redis存储字符串的区别
C 语言字符串存储
  • 基于字符数组实现,以 '\0' 作为字符串结束标识;
Redis 字符串存储
  • 底层通过 SDS 结构的 char buf[] 存储二进制数据(任何类型数据均可转换为二进制存储);
  • 具备二进制安全特性:存入的原始数据(含 '\0' 等特殊字符)不会被修改或截断,取出的数据与存入完全一致;
核心差异
  • C 语言字符串遇 '\0' 即判定结束,而 Redis 的 SDS 不依赖 '\0' 识别结束,也不会处理存储的二进制数据,保证数据完整性。

4.1.2 命令

  1. 赋值与取值

    #set支持插入/更新
    set key value
    get key

当键不存在时返回空结果。

只有 key 不存在时才赋值

复制代码
setnx key value

2.向尾部追加值

复制代码
append key value

append的作用是向键值的末尾追加value。
如果键不存在则将该键的值设置为value,即相当于 set key value。返回值是追加后字符串的总长度。

  1. 获取字符串长度

    strlen key

strlen命令返回键值的长度,如果键不存在则返回0。

  1. 同时设置/获取多个键值

    mset key value [key value ...]
    mget key [key ...]

5.获取value指定位置的内容

复制代码
getrange key start end
  • key:要操作的 Redis 键;
  • start:截取的起始下标(从 0 开始);
  • end:截取的结束下标(包含该下标);
  • 核心:按下标截取 value 的子字符串,下标支持负数(-1 表示最后一个字符,-2 表示倒数第二个,以此类推)。
  1. 删除key

    删单个 key(核心命令)
    del key
    删多个 key(空格分隔)
    del key1 key2 key3

4.1.3 方法

  1. String 类型核心操作

|---------|-----------------------------------------|-------------|---------------------|
| 功能 | StringRedisTemplate 方法 | 对应 Redis 命令 | 代码中的作用 |
| 单个赋值 | opsForValue().set(key, value) | SET | 给指定 key 设置字符串值 |
| 单个取值 | opsForValue().get(key) | GET | 获取指定 key 的字符串值 |
| 尾部追加 | opsForValue().append(key, value) | APPEND | 向 key 的值尾部追加字符串 |
| 不存在时赋值 | opsForValue().setIfAbsent(key, value) | SETNX | 仅当 key 不存在时赋值,返回布尔值 |
| 带过期时间赋值 | opsForValue().set(key, value, 时长, 时间单位) | SETEX | 赋值 + 设置过期时间(自动删除) |
| 获取并覆盖 | opsForValue().getAndSet(key, newValue) | GETSET | 获取旧值并立刻设置新值 |
| 截取子串 | opsForValue().get(key, start, end) | GETRANGE | 按下标截取 key 对应值的子字符串 |
| 批量赋值 | opsForValue().multiSet(Map) | MSET | 一次性设置多个 key-value |
| 批量取值 | opsForValue().multiGet(List) | MGET | 一次性获取多个 key 的值 |

  1. Key 通用操作

|-------------|---------------------------------------------------|------------------|-----------------------|
| 功能 | StringRedisTemplate 方法 | 对应 Redis 命令 | 代码中的作用 |
| 删除单个 key | delete(key) | DEL | 删除指定 key |
| 删除多个 key | delete(List) | DEL key1 key2... | 一次性删除多个 key |
| 判断 key 是否存在 | hasKey(key) | EXISTS | 检查 key 是否存在,返回布尔值 |
| 清空当前数据库 | getConnectionFactory().getConnection().flushDb() | FLUSHDB | 清空当前 Redis 库的所有 key |
| 回显测试 | getConnectionFactory().getConnection().echo(字节数组) | ECHO | 调试 Redis 连接(返回传入的字符串) |

  1. 结论
  • String 类型操作的核心套路:stringRedisTemplate.opsForValue().xxx();
  • Key 通用操作直接调用 stringRedisTemplate.xxx()(如 delete/hasKey);
  • 底层原生命令(如 FLUSHDB/ECHO)需通过 getConnection() 获取连接后执行;
  1. 代码

    package com.qcby.springbootredis;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    @SpringBootTest
    public class StringTest {
    // 注入 SpringBoot 提供的 StringRedisTemplate(替代 Jedis)
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**

    • 赋值、取值、追加、批量操作
      */
      @Test
      public void testHello() {
      try {
      // 1. 赋值(对应 set 命令)
      stringRedisTemplate.opsForValue().set("name", "minxr");
      // 取值(对应 get 命令)
      String ss = stringRedisTemplate.opsForValue().get("name");
      System.out.println(ss); // 输出 minxr

      复制代码
       // 2. 向尾部追加(对应 append 命令)
       stringRedisTemplate.opsForValue().append("name", "jintao");
       ss = stringRedisTemplate.opsForValue().get("name");
       System.out.println(ss); // 输出 minxrjintao
      
       // 3. 覆盖数据
       stringRedisTemplate.opsForValue().set("name", "jintao");
       System.out.println(stringRedisTemplate.opsForValue().get("name")); // 输出 jintao
      
       // 4. 删除key(对应 del 命令)
       stringRedisTemplate.delete("name");
       System.out.println(stringRedisTemplate.opsForValue().get("name")); // 输出 null
      
       // 5. 批量设置/获取(对应 mset、mget 命令)
       // 替换 Map.of() 适配Java 8
       Map<String, String> multiSetMap = new HashMap<>();
       multiSetMap.put("name", "minxr");
       multiSetMap.put("jarorwar", "aaa");
       stringRedisTemplate.opsForValue().multiSet(multiSetMap);
      
       // 替换 List.of() 适配Java 8
       List<String> multiGetList = new ArrayList<>();
       multiGetList.add("name");
       multiGetList.add("jarorwar");
       System.out.println(stringRedisTemplate.opsForValue().multiGet(multiGetList)); // 输出 [minxr, aaa]

      } catch (Exception e) {
      e.printStackTrace();
      }
      }

    /**

    • key相关操作
      */
      @Test
      public void testKey() {
      System.out.println("=============key==========================");
      // 清空当前库(对应 flushdb 命令)
      //先获取 Redis 底层连接(相当于拿到 redis-cli 的连接),在执行命令
      stringRedisTemplate.getConnectionFactory().getConnection().flushDb();
      // 回显(对应 echo 命令)
      System.out.println(new String(stringRedisTemplate.getConnectionFactory().getConnection().echo("foo".getBytes())));

      // 判断key是否存在(对应 exists 命令)
      System.out.println(stringRedisTemplate.hasKey("foo")); // 输出 false
      stringRedisTemplate.opsForValue().set("key", "values");
      System.out.println(stringRedisTemplate.hasKey("key")); // 输出 true
      }

    /**

    • String 类型完整操作
      */
      @Test
      public void testString() {
      System.out.println("==String==");
      try {
      System.out.println("=============String==========================");
      // 清空当前库
      stringRedisTemplate.getConnectionFactory().getConnection().flushDb();

      复制代码
       // 1. 存储数据
       stringRedisTemplate.opsForValue().set("foo", "bar");
       System.out.println(stringRedisTemplate.opsForValue().get("foo")); // 输出 bar
      
       // 2. 若key不存在则存储(对应 setnx 命令)
       Boolean setNx = stringRedisTemplate.opsForValue().setIfAbsent("foo", "foo not exits");
       System.out.println(setNx); // 输出 false(因为 foo 已存在)
       System.out.println(stringRedisTemplate.opsForValue().get("foo")); // 输出 bar
      
       // 3. 覆盖数据
       stringRedisTemplate.opsForValue().set("foo", "foo update");
       System.out.println(stringRedisTemplate.opsForValue().get("foo")); // 输出 foo update
      
       // 4. 追加数据
       stringRedisTemplate.opsForValue().append("foo", " hello, world");
       System.out.println(stringRedisTemplate.opsForValue().get("foo")); // 输出 foo update hello, world
      
       // 5. 设置有效期并存储(对应 setex 命令)
       stringRedisTemplate.opsForValue().set("foo", "foo not exits", 2, TimeUnit.SECONDS);
       //立刻查foo:此时还没到2秒,能拿到值 → 输出 foo not exits
       System.out.println(stringRedisTemplate.opsForValue().get("foo")); // 输出 foo not exits
       //让当前执行代码的线程"暂停3秒"
       Thread.sleep(3000);
       //3秒后再查foo:2秒过期时间已到,Redis已删了foo → 输出 null
       System.out.println(stringRedisTemplate.opsForValue().get("foo")); // 输出 null
      
       // 6. 获取并更改数据(对应 getset 命令)
       stringRedisTemplate.opsForValue().set("foo", "foo update");
       System.out.println(stringRedisTemplate.opsForValue().getAndSet("foo", "foo modify")); // 输出 foo update
      
       // 7. 截取value(对应 getrange 命令)
       System.out.println(stringRedisTemplate.opsForValue().get("foo", 1, 3)); // 输出 oo空格
      
       // 8. 批量设置/获取
       Map<String, String> msetMap = new HashMap<>();
       msetMap.put("mset1", "mvalue1");
       msetMap.put("mset2", "mvalue2");
       msetMap.put("mset3", "mvalue3");
       msetMap.put("mset4", "mvalue4");
       stringRedisTemplate.opsForValue().multiSet(msetMap);
      
       List<String> mgetList = new ArrayList<>();
       mgetList.add("mset1");
       mgetList.add("mset2");
       mgetList.add("mset3");
       mgetList.add("mset4");
       System.out.println(stringRedisTemplate.opsForValue().multiGet(mgetList)); // 输出 [mvalue1, mvalue2, mvalue3, mvalue4]
      
       // 9. 删除多个key
       List<String> delList = new ArrayList<>();
       delList.add("foo");
       delList.add("foo1");
       delList.add("foo3");
       stringRedisTemplate.delete(delList);

      } catch (Exception e) {
      e.printStackTrace();
      }
      }

    }

相关推荐
Yungoal2 小时前
C++链接并操作嵌入式数据库SQLite
数据库·c++·sqlite
一个有温度的技术博主2 小时前
Redis系列一:了解Nosql与关系型数据库
数据库·redis·nosql
云边云科技_云网融合2 小时前
百度首页中宇联云计算SD-AIoT:万物互联时代,从 “能连上” 到 “用得放心” 的技术革命
网络·数据库·人工智能
草莓熊Lotso2 小时前
Linux 进程间通信之 System V 共享内存:IPC 的原理与实战
linux·运维·服务器·c语言·数据库·c++·人工智能
尽兴-2 小时前
从零到精通:Redis 7 核心数据结构实战与单机部署指南
数据结构·数据库·redis·部署·redis7
q5431470872 小时前
Spring TransactionTemplate 深入解析与高级用法
java·数据库·spring
6+h2 小时前
【java IO】IO体系结构 + File类详解
java·数据库·php
happymaker06262 小时前
JDBC(MySQL)——DAY05(DAO设计模式,JDBC事务处理,阿帕奇工具类)
数据库·mysql·设计模式