redis 二. string 应用场景及底层分析

2023-11-05

一. 简单命令示例

  1. String字符串类型,一个key对应value最大可以存512
  2. 简单命令使用示例
//1.单个键值对插入与获取
set k1 v1
get k1

//2.一次多个键值对插入与获取
mset k1 v1 k2 v2 k3 v3
mget k1 k2 k3

//3.递增数字 INCR key,每执行一次该命令,对应该key的值累计加1
//存储 ki 对应value 为1
set ki 1
//每执行一次对应ki的值累计加1(思考该方法可以用在什么功能上? 点赞量)
INCR ki 

//4.递减数字 DECR key,每执行一次该命令,对应该key的值累计减1
DECR ki

//5.获取字符串长度
STRLEN k1

//6.分布式锁
setnx key value

//EX: 指定key多少秒后过期
//PX: 指定key多好毫秒后过期
//NX: 当key不存在时才创建,等同于setnx
//XX: 当key不存在时才创建,存在则覆盖
#set key value [EX seconds][PX milliseconds][NX|XX]
//使用举例
set orderK aaa ex 10 nx

二. java 操作示例

基础

  1. 操作 String 类型,二进制安全的。意思是可以包含任何数据。比如jpg图片或者序列化的对象 ,最基本的数据类型,一个键最大能存储512MB。
	@Test
    public void test01() {

        //创建操作redis中String类型数据的对象 ValueOperations
        ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();

        //1.添加数据set()添加数据(如果添加这个数据在库中已经存在就变为了修改)
        valueOperations.set("username", "mingming");

        /*2.以层级关系目录形式添加数据*/
        valueOperations.set("user:01", "wwww");
        valueOperations.set("user:01", "cccc");

        //3.添加多条数据multiSet()
        //map中的key为redis的key,map中的值为redis的值
        Map<String,String> stringMap=new HashMap<>();
        stringMap.put("数据1","值1");
        stringMap.put("数据2","值2");
        stringMap.put("数据3","值3");

        valueOperations.multiSet(stringMap);

        //4.查询
        Object username=valueOperations.get("username");

        //5.查询多条,以集合中的数据为key进行查询
        List<String> keyStr=new ArrayList<>();
        keyStr.add("数据1");
        keyStr.add("数据2");
        keyStr.add("数据3");
        List<String> valL=valueOperations.multiGet(keyStr);

        //6.删除指定key数据
        stringRedisTemplate.delete("username");

        //6.模糊匹配
        Set<String> keys = stringRedisTemplate.keys("noteUserListenedPoi:" + "*");

        //7.批量删除
        stringRedisTemplate.delete(keys);

    }

setnx() 与 getset()

  • setnx() 向redis中存储一个key-value,如果redis库中已存在,当前存储失败返回0,如果不存在,存储成功,返回1
  • get(key) 获取key的值,如果存在,则返回;如果不存在,则返回nil;
  • getset()命令:这个命令主要有两个参数 getset(key, newValue)。该方法是原子的,对key设置newValue这个值,并且返回key原来的旧值。
 	@Autowired
    public Jedis jedis;

    @Autowired
    public JedisPool jedisPool;

    @Test
    public void test() {
        //1.建立redis连接
        Jedis conn = jedisPool.getResource();

        long currentTime = System.currentTimeMillis();//当前时
        String lockTimeDuration = String.valueOf(currentTime);
        //将当前时间作为value 存储到redis中,存储成功返回1,否则返回0
        Long i = jedis.setnx("keys", lockTimeDuration);
    }

三. 使用场景举例

  1. 分布式锁 setnx
  2. 点赞 DECR

统计点击次数

  1. 使用String类型,与incr 命令实现喜欢的文章,热搜案例
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ArticleController {

    public static final String likeK = "acticle";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 使用String类型,调用increment(key)对一个key进行累计加1,用来统计点击量等
     * 注意点: 该方式适用与qps不高的小厂,假设qps超过10万,例如热搜,一瞬间可能会打爆redis
     * //解决方式一: 有些统计精确度不高的,该累计数字到一定程度后就不回继续累计直接返回,例如显示"10w+"
     * //解决方式二: 适用redis的set类型,时间片去解决
     * @param acticleId 
     * @return
     */
    @GetMapping("/likeActicle")
    public Long likeArticle(String acticleId) {
        String key = likeK + acticleId;
        long l = stringRedisTemplate.opsForValue().increment(key);
        return l;
    }
}

四. 底层分析

  1. 在redis中一个string最大存储512

  2. 注意点String同一个数据类型有三种编码格式: int, embstr, raw (出现三种数据类型的原因是为了精确的利用并解决内存)

  3. int: 保存long型(长整型)的64位,8个字节有符号整数,最多19位,例如"set key 11"存储的是一个纯数字类型,到底层就使用int编码格式

  4. redis在启动时会预先建立10000个分别存储了0-9999的redisObject共享变量,当我们set 字符串为0-10000之间的话则使用共享变量即可,不需要再建立新对象,并且当前存储的数字字符串如果不超过"9223372036854775807"使用int编码格式,既redisObject中type=“REDIS_STRING”, encoding=“OBJ_ENCODING_INT”,整个结构如下
    在这里插入图片描述

  5. 注意点有个范围,当set 的数字超过"9223372036854775807"再次查看这个key的编码就会变为embstr
    在这里插入图片描述

  6. 补充点: 只有整数才会使用int编码格式,如果是浮点数,redis会现将浮点数转化为字符串值,然后进行保存
    在这里插入图片描述

  7. embstr编码格式又叫做SDS简单动态字符串,保存长度小于44字节的字符串,embstr既embedded string 又叫做嵌入式字符串,此时redisObject中的type=“OBJ_STRING”, encoding =“OBJ_ENCODING_ENBSTR”,整个redisObject结构在原int基础上嵌入了sds结构,如下图
    在这里插入图片描述

  8. raw编码格式: 保存大于44字节的字符串

  9. 注意点:在编码格式为embstr时,embsetr实际是只读的,当我们对embstr格式数据进行修改时,会先将其转换为raw格式,既所有修改后embstr格式的数据都是raw,type=“REDIS_STRING”, encoding=“OBJ_ENCODING_RAW”
    在这里插入图片描述
    在这里插入图片描述

  10. 示例在这里插入图片描述

  11. 总结:
    在这里插入图片描述

SDS 嵌入式动态字符串

  1. redis使用c编写,在c语言中使用buf数组存储字符串,而redis在c基础上重新封装了一个存储字符串的结构也就是SDS ,有叫做简单动态字符串
    在这里插入图片描述
  2. SDS结构解释: (只是拿sdshdr8做个示例,在sds.h源码中有各个该结构)
    在这里插入图片描述
  3. 查看sds.h源码发现提供了多种sdshdr5,8,16,64…存储字符串接口,为什么没有选择c的buf数组存储字符串,而是分装了多个sdshdr结构体
    在这里插入图片描述

1)通过不同sdshdX结构体存储不同大小的字符串,所以提供了多个sdshdX结构体
2)封装新结构体sds,存储字符串的好处是: c语言中没有java中的String类型,在c中适用字符串时通过char[]数组实现的,假设想要获取一个字符串的长度,需要从头开始遍历,到’\0’,而sds结构体中有一个len属性,表示当前字符串的长度,可以在O(1)情况下直接拿到,不需要像c以前一样遍历一遍字符串才可以
3)sds结构体中有alloc属性表示字符串最大字节长度,free属性,表示以分配而未使用的空间大小,这样就不需要考虑内存分配的问题
在这里插入图片描述

再次总结

  1. redis使用c编写, c语言中没有字符串类型, 封装了专门的SDS对象,用来存储,内部存在
  1. buf[]数组属性: 字节数组,用于保存实际数据
  2. len属性:当前保存数据的buf数组长度
  3. free属性: 数组中未使用的字节数量
  4. alloc属性: 当前字符串数组总共占用分配内存大小
  1. 基于以上属性sds动态字符串具有了以下优点:
  1. 常数复杂度获取字符串长度: 在获取字符串长度时,可以直接通过sds的len属性获取,复杂度为0(1)
  2. 减少缓冲区溢出: 修改sds时,会检查 free属性剩余空间的大小,如果不足将会额外申请(也就是空间预分配机制)
  3. 实现了空间预分配机制: 在对SDS 进行修改后会判断(也就是下面的扩容策略)

3.1 newlen 如果小于 1MB时,会分配 alloc 等于 2 * newlen,此时 free = len, 举例: SDS修改后len变为13个字节,程序也会分配 13 字节的未使用空间,SDS的 buf 数组此时长度将变成 13 + 13 + 1 = 27 字节(额外的一字节用于保存空字符)
3.2 newlen 如果大于等于 1MB时,会分配 1MB 的未使用空间。举例: SDS修改后len 变成30MB,程序会分配 1MB 的未使用空间,SDS 的 buf 数组的实际长度将为 30MB + 1MB + 1byte

  1. 惰性释放: 当sds需要缩短字符串时, 并不立即回收内存,而是使用 free 属性,将这些字节的数量记录起来,下次使用时再回收
  2. 二进制安全: SDS的API都是二进制安全的,存放在buf数组里的数据
  1. 根据空间分配机制了解到sds的扩容策略:
  1. 若剩余空闲长度 avail 大于新增内容的长度 addlen,直接在数组 buf 末尾追加即可,无须扩容
  2. 若剩余空闲长度 avail 小于或等于新增内容的长度 addlen,则分情况讨论:新增后总长度 len+addlen <1MB 的,按新长度的 2倍 扩容;新增后总长度 len+addlen > 1MB 的,按新长度加上 1MB 扩容。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

redis 二. string 应用场景及底层分析 的相关文章

  • 在 JTable 中移动行

    我使用 MVC 模式 并且有一个如下所示的 JTable List
  • 如何使用 FileChannel 将一个文件的内容附加到另一个文件的末尾?

    File a txt好像 ABC File d txt好像 DEF 我正在尝试将 DEF 附加到 ABC 所以a txt好像 ABC DEF 我尝试过的方法总是完全覆盖第一个条目 所以我总是最终得到 DEF 这是我尝试过的两种方法 File
  • 如何在 JFace 的 TableViewer 中创建复选框?

    我创建了一个包含两列的 tableViewer 我想将其中一列设为复选框 为此 我创建了一个 CheckBoxCellEditor 但我不知道为什么它不起作用 名为 tableName 的列显示其值正常 色谱柱规格如下 String COL
  • 我需要在 Spring 中检查每个控制器中的有效会话吗? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 假设在 Spring Mvc 的 Web 应用程序中 我们是否需要检查每个控制器或 jsps 中的有效会话 我该如何解决 MVC 中的
  • ElasticBeanstalk Java,Spring 活动配置文件

    我正在尝试通过 AWS ElasticBeanstalk 启动 spring boot jar 一切正常 配置文件为 默认 有谁知道如何为 java ElasticBeanstalk 应用程序 不是 tomcat 设置活动配置文件 spri
  • ExceptionConverter:java.io.IOException:文档没有页面。我正在使用 iText

    当我执行下面的代码时 File f new File c sample pdf PdfWriter getInstance document new FileOutputStream f document open System out p
  • IntelliJ IDEA 创建的 JAR 文件无法运行

    我在 IntelliJ 中编写了一个跨越几个类的程序 当我在 IDE 中测试它时它运行良好 但是 每当我按照教程将项目制作成 jar 可执行文件时 它就不会运行 双击 out 文件夹中的文件时 该文件不会运行 并显示 无法启动 Java J
  • 在数据流模板中调用 waitUntilFinish() 后可以运行代码吗?

    我有一个批处理 Apache Beam 作业 它从 GCS 获取文件作为输入 我的目标是根据执行后管道的状态将文件移动到两个 GCS 存储桶之一 如果管道执行成功 则将文件移动到存储桶 A 否则 如果管道在执行过程中出现任何未处理的异常 则
  • 如何在 Java 中禁用 System.out 以提高速度

    我正在用 Java 编写一个模拟重力的程序 其中有一堆日志语句 到 System out 我的程序运行速度非常慢 我认为日志记录可能是部分原因 有什么方法可以禁用 System out 以便我的程序在打印时不会变慢 或者我是否必须手动检查并
  • Java 页面爬行和解析之 Crawler4j 与 Jsoup

    我想获取页面的内容并提取其中的特定部分 据我所知 此类任务至少有两种解决方案 爬虫4j https github com yasserg crawler4j and Jsoup http jsoup org 它们都能够检索页面的内容并提取其
  • OnClick 事件中的 finish() 如何工作?

    我有一个Activity一键退出Activity 通过layout xml我必须设置OnClick事件至cmd exit调用 this finish 效果很好 public void cmd exit View editLayout thi
  • 请求位置更新参数

    这就是 requestLocationUpdates 的样子 我使用它的方式 requestLocationUpdates String provider long minTime float minDistance LocationLis
  • 制作java包

    我的 Java 类组织变得有点混乱 所以我要回顾一下我在 Java 学习中跳过的东西 类路径 我无法安静地将心爱的类编译到我为它们创建的包中 这是我的文件夹层次结构 com david Greet java greeter SayHello
  • 使用 SAX 进行 XML 解析 |如何处理特殊字符?

    我们有一个 JAVA 应用程序 可以从 SAP 系统中提取数据 解析数据并呈现给用户 使用 SAP JCo 连接器提取数据 最近我们抛出了一个异常 org xml sax SAXParseException 字符引用 是无效的 XML 字符
  • android Accessibility-service 突然停止触发事件

    我有一个 AccessibilityService 工作正常 但由于开发过程中的某些原因它停止工作 我似乎找不到这个原因 请看一下我的代码并告诉我为什么它不起作用 public class MyServicee extends Access
  • com.jcraft.jsch.JSchException:身份验证失败

    当我从本地磁盘上传文件到远程服务器时 出现这样的异常 com jcraft jsch JSchException Auth fail at org apache tools ant taskdefs optional ssh Scp exe
  • 中断连接套接字

    我有一个 GUI 其中包含要连接的服务器列表 如果用户单击服务器 则会连接到该服务器 如果用户单击第二个服务器 它将断开第一个服务器的连接并连接到第二个服务器 每个新连接都在一个新线程中运行 以便程序可以执行其他任务 但是 如果用户在第一个
  • JAVA - 如何从扫描仪读取文件中检测到“\n”字符

    第一次海报 我在读取文本文件的扫描仪中读取返回字符时遇到问题 正在读取的文本文件如下所示 test txt start 2 0 30 30 1 1 90 30 0 test txt end 第一行 2 表示两个点 第二行 位置索引 0 xp
  • javax.persistence.Table.indexes()[Ljavax/persistence/Index 中的 NoSuchMethodError

    我有一个 Play Framework 应用程序 并且我was使用 Hibernate 4 2 5 Final 通过 Maven 依赖项管理器检索 我决定升级到 Hibernate 4 3 0 Final 成功重新编译我的应用程序并运行它
  • Jackson 将单个项目反序列化到列表中

    我正在尝试使用一项服务 该服务为我提供了一个带有数组字段的实体 id 23233 items name item 1 name item 2 但是 当数组包含单个项目时 将返回该项目本身 而不是包含一个元素的数组 id 43567 item

随机推荐

  • 动态动态规划(DDP)

    1 Problem E Codeforces 一 题目大意 给你一个无向图 第i和i 1条边的权值是w i 问你每个点不在自己原本的点的代价是多少 会有q组询问 表示修改第i条边的权值 二 解题思路 可以观察到 完成这个操作需要每条边经过两
  • [LeetCode]初级算法-字符串- 实现strStr()

    标题 实现strStr 实现 strStr 函数 给定一个 haystack 字符串和一个 needle 字符串 在 haystack 字符串中找出 needle 字符串出现的第一个位置 从0开始 如果不存在 则返回 1 示例 1 输入 h
  • linux防火墙启动、停止、查看

    停止 防火墙 service iptables stop 启动防火墙 service iptables start 查看防火墙配置 iptables L n 修改的内容只是暂时保存在内存中 如果重启后还要生效 则要保存一下 service
  • Web Storage是什么?Web Storage详解

    Web Storag是HTML5引入的一个非常重要的功能 可以将数据存储在本地 如保存用户的偏好设置 复选框的选中状态 文本框默认填写的值等 用户在浏览器中刷新网页时 网页通过Web Storage就可以知道用户之前所做的一些修改 而不需要
  • Autoware 1.14(WSL2) 与LG SVL Simulator(Win11)联合仿真

    参考Couldn t find executable named rqt lgsvl simulator configurator below home autoware Autoware ros in li4692625的博客 CSDN博
  • Hyperledger Fabric核心配置文件(1)

    1 core yaml core yaml配置文件是Peer节点的示例配置文件 具体路径在fabric samples config目 录下 该core yaml示例配置文件共指定了如下六大部分内容 1 日志部分 日志记录级别有6种 CRI
  • JDBC访问数据库

    一 简介 JDBC 全称 Java DataBase Connection 数据库连接技术 可以根据驱动包连接不同类型的数据库 二 JDBC API JDBC API是java中位于java sql包下的一个数据库访问统一接口 通过它来跟数
  • 无监督学习KMeans学习笔记和实例

    KMeans算法是一种简单的算法 能够快速 高效的对数据集进行聚类 一般只要通过几次迭代即可 KMeans可以作为一种聚类工具 同时也可以作为一种降维的方式进行特征降维 KMeans可以通sklearn cluster kmeans中进行调
  • 测试 开发 5 年从外包 18K 跳槽去字节 28K+12,啃完这份笔记你也可以

    软件测试是一个付出就有回报的工作 可能很多人会说软件测试就是吃青春饭 然而其他工作又何尝不是 没有哪一家公司养尸位素餐之人 大龄员工有被辞退的 也有没被辞退的 干任何职业 抱着一劳永逸的心态 在岗位上开始混的中青年 早就该辞了 粉丝小王转行
  • 测试方法——边界值法

    边界值测试方法 边界值方法是一种比较常用的测试方法 在很多软件测试中都会应用到 一 应用条件 只要有输入框输入数据的地方 就可以用边界值这一方法来测试 一般与等价类划分共同使用 找到有效数值和无效数值之间的分界点及其两边的点进行测试 二 测
  • Jmeter进阶使用指南-使用参数化

    Apache JMeter是一个广泛使用的开源负载和性能测试工具 在进行性能测试时 我们经常需要模拟不同的用户行为和数据 这时候 参数化就显得尤为重要 此文主要介绍如何在JMeter中使用参数化 什么是参数化 参数化是一种将静态值替换为动态
  • 深入理解HashMap和LinkedHashMap的区别

    简介 我们知道HashMap的变量顺序是不可预测的 这意味着便利的输出顺序并不一定和HashMap的插入顺序是一致的 这个特性通常会对我们的工作造成一定的困扰 为了实现这个功能 我们可以使用LinkedHashMap LinkedHashM
  • 【配电变电站的最佳位置和容量】基于遗传算法的最优配电变电站放置(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码实现 1 概述 基于遗传算法的最优配电变电站放置 为了实现
  • iseacms1.0漏洞复现

    iseacms1 0漏洞复现 作者 admin 时间 2021 06 29 分类 漏洞复现 Index php源码 文件包含 参数转义了 0 利用方式有限在网站目录有phpinfo php文件的前提下 payload为 index r te
  • 【十三】Nacos 服务注册和配置中心

    目录 Nacos 初识 Nacos 服务部署 注册中心服务部署 服务提供者注册到Nacos 服务消费者从Nacos获取服务 负载均衡 Nacos 服务详解 实列服务详情详解 Nacos 初识 Nacos Dynamic Naming and
  • Android 输入框的输入提示效果(AutoCompleteTextView)

    在一些体验较好的APP中 输入框输入时会有相应的提示 让人能够很快的通过点击提示进入下一步 这里 我就通过自己构思 实现了一个通过 SharedPreferences 保存的输入提示 demo 实现 1 实现一个 SharedPrefere
  • opencv项目实战(二)——文档扫描OCR识别

    一 项目描述 二 代码详解 2 1 预定义参数 2 2 辅助函数 2 3 文档矫正 2 4 文档识别 三 项目完整代码 一 项目描述 目的 将图片中的文档矫正 并识别文档内容 输入与输出 方法流程 核心思想 采用tesseract ocr进
  • 前端在vue2框架中导出PDF

    1 需求 导出具有页眉页脚 页码的Pdf 并且解决Pdf分割的问题 2 实现思路 该需求主要的难点在于分页的时候容易出现分割问题 并且要将页眉页脚加进去 实现的大概思路 1 先使用jsPDF html2canvas将页面可以导出 2 第一页
  • PHP 8突破性变化

    新的PHP首要版别PHP8估计将于2020年底发布 它现在正处于十分活泼的开发中 所以在接下来的几个月里 开发速度和开发进程或许会有很大的改动 在这篇文章中 我会罗列出PHP8中会发作的一些改动 新功能 性能改善和突破性改动 由于PHP8是
  • redis 二. string 应用场景及底层分析

    String 字符串类型 一 简单命令示例 二 java 操作示例 基础 setnx 与 getset 三 使用场景举例 统计点击次数 四 底层分析 SDS 嵌入式动态字符串 再次总结 一 简单命令示例 String字符串类型 一个key对