redis从零开始(1)----五种基本类型:string/hash

news2025/2/25 11:06:01

认识redis

NoSQL

Nosql = not only sql,泛指非关系型数据库,与之相对的是RDBMS(Relational Database Management System),即关系型数据库
关系型数据库:列+行,同一个表下数据的结构是一样的。
非关系型数据库:数据存储没有固定的格式,并且可以进行横向扩展。
redis就是当下最好的NoSQL

Nosql和RDBMS的区别

  • RDBMS

    • 组织化结构
    • 固定SQL
    • 数据和关系都存在单独的表中(行列)
    • DML(数据操作语言)、DDL(数据定义语言)等
    • 严格的一致性(ACID): 原子性、一致性、隔离性、持久性
    • 基础的事务
  • NoSQL

    • 不仅仅是数据
    • 没有固定查询语言
    • 键值对存储(redis)、列存储(HBase)、文档存储(MongoDB)、图形数据库(不是存图形,放的是关系)(Neo4j)
    • 最终一致性(BASE):基本可用、软状态/柔性事务、最终一致性

redis是什么

Redis(Remote Dictionary Server),即远程字典服务。
数据都是缓存在内存中,查询和修改很快。redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

准备工作

# 安装redis
brew install redis

# 启动redis服务端
redis-server

# 连接redis: IP + 端口号
redis-cli -h 127.0.0.1 -p 6379

五种基本数据结构

string

简介
  • String类型是redis的最基础的数据结构,也是最经常使用到的类型。而且其他的四种类型多多少少都是在字符串类型的基础上构建的,所以String类型是redis的基础。
  • String 类型的值最大能存储 512MB,这里的String类型可以是简单字符串、复杂的xml/json的字符串、二进制图像或者音频的字符串、以及可以是数字的字符串
底层实现

String 类型的底层的数据结构实现主要是 int 和 SDS(Simple dynamic string,简单动态字符串),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 空间是否满足要求,如果空间不够会自动扩容,所以不会导致缓冲区溢出的问题。

string对象的内部编码有三种:int、raw、embstr(后两种的实现都是SDS)

  • 如果string保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在对象结构的ptr属性里。
  • 如果string对象保存的是一个长度<=32byte的字符串,那么字符串对象将使用SDS来保存,并将编码方式设为embstr,这是一种专门优化了保存短字符串的编码方式
    embstr
  • 如果string对象保存的是一个长度<=32byte的字符串,那么字符串对象将使用SDS来保存,并将编码方式设为raw
    raw

embstr和raw虽然都用SDS来保存,但是embstr会通过一次内存分配函数来分配一块连续的内存空间来保存redisObject和SDS,而raw编码会通过调用两次内存分配函数来分别分配两块空间来保存redisObject和SDS

  • embstr优点:
    • embstr编码将创建字符串对象所需的内存分配次数从 raw 编码的两次降低为一次
    • 释放 embstr编码的字符串对象同样只需要调用一次内存释放函数
    • 因为embstr编码的字符串对象的所有数据都保存在一块连续的内存里面可以更好的利用 CPU 缓存,从而提升性能
  • embstr缺点:
    • 如果字符串的长度增加需要重新分配内存时,整个redisObject和SDS都需要重新分配空间,即embstr编码的字符串对象实际上是只读的,redis没有为embstr编码的字符串对象编写任何相应的修改程序。
    • 当我们对embstr编码的字符串对象执行任何修改命令(例如append)时,程序会先将对象的编码从embstr转换成raw,然后再执行修改命令
使用
// 设置指定 key 的值。
redis 127.0.0.1:6379> SET test redis
OK
// 删除key
127.0.0.1:6379> del test
(integer) 1
127.0.0.1:6379> get test
(nil)
// 获取指定 key 的值。
redis 127.0.0.1:6379> GET test
"redis"
// 获取key的值的子字符串
127.0.0.1:6379> getrange test 0 1
"re"
// 将key的值更新为新值,返回旧值
127.0.0.1:6379> getset test redis1
"redis"
// 当key不存在时才能设置,即只能新建
127.0.0.1:6379> setnx test redis
(integer) 0
127.0.0.1:6379> setnx qian redis
(integer) 1
// 返回key所存储的值的长度
127.0.0.1:6379> strlen qian
(integer) 5
// setex:将值value关联到key,并将key的过期时间设为seconds(以秒为单位)。
127.0.0.1:6379> set qian redis
OK
127.0.0.1:6379> setex qian 10 redis11
OK
127.0.0.1:6379> get qian	// 更新了key的值
"redis11"
127.0.0.1:6379> get qian	// 过了10秒就过期了
(nil)
// msetes:同上,但是过期时间为毫秒
msetex qian 10 redis11
应用场景

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

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

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

# 初始化文章的阅读量
> SET aritcle:readcount:1001 0
OK
#阅读量+1
> INCR aritcle:readcount:1001
(integer) 1
# 获取对应文章的阅读量
> GET aritcle:readcount:1001
"3"

3、分布式锁
SET 命令有个 NX 参数可以实现「key不存在才插入」,可以用它来实现分布式锁:如果key不存在,则插入成功,可以用来表示加锁成功;如果key存在,则加锁失败。

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

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

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

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

这样一来,就通过使用 SET 命令和 Lua 脚本在 Redis 单节点上完成了分布式锁的加锁和解锁。
4、共享session信息
通常后台系统会使用session来保存用户的会话状态,这些 Session 信息会被保存在服务器端,但这只适用于单系统应用,如果是分布式系统此模式将不再适用。

用户一的 Session 信息被存储在服务器一,但第二次访问时用户一被分配到服务器二,这个时候服务器并没有用户一的 Session 信息,就会出现需要重复登录的问题,问题在于分布式系统每次会把请求随机分配到不同的服务器。
分布式系统存储session
因此,我们需要借助 Redis 对这些 Session 信息进行统一的存储和管理,这样无论请求发送到那台服务器,服务器都会去同一个 Redis 获取相关的 Session 信息,这样就解决了分布式系统下 Session 存储的问题。
分布式系统使用一个redis存储session

Hash

简介
  • hash是一个键值对(key-value)集合,它是一个 string 类型的 field 和 value 的映射表
  • redis本身就是一个key-value型数据库,因此hash数据结构相当于在value中又套了一层key-value型数据,所以redis中hash数据结构特别适合存储关系型对象
  • 可以像数据库中update一个属性一样只修改某一项属性值
  • 如果哈希类型元素个数小于512个,redis使用压缩列表作为底层结构;否则的话会使用redis作为底层结构。另外,在Redis 7.0中,压缩列表已经废弃,交由listpack实现
使用
// key = qian,然后设置了他的一些value,“name/age/sex”
127.0.0.1:6379> hmset qian name "qjl" age "23" sex "male"
OK
127.0.0.1:6379> hgetall qian
1) "name"
2) "qjl"
3) "age"
4) "23"
5) "sex"
6) "male"
// 删除key的某个字段
127.0.0.1:6379> hdel qian sex
(integer) 1
// 查看key的某个字段是否存在
127.0.0.1:6379> hexists qian sex
(integer) 0
// 查看key的某个字段
127.0.0.1:6379> hget qian sex
(nil)
// 获取哈希表中的所有字段
127.0.0.1:6379> hkeys qian
1) "name"
2) "age"
// 获取哈希表中字段的数量
127.0.0.1:6379> hlen qian
(integer) 2
// 更改key的值
127.0.0.1:6379> hset qian name spiderman
(integer) 0
127.0.0.1:6379> hgetall qian
1) "name"
2) "spiderman"
3) "age"
4) "23"
// 删除key
127.0.0.1:6379> del qian
(integer) 1
127.0.0.1:6379> hgetall qian
(empty array)
使用场景

1、缓存对象
存储对象时,一般使用用 String + Json 存储,对象中某些频繁变化的属性可以考虑抽出来用 Hash 类型存储。

# 存储一个哈希表uid:1的键值
> HMSET uid:1 name qian age 23
2
# 存储一个哈希表uid:2的键值
> HMSET uid:2 name zhou age 24
2
# 获取哈希表用户id为1中所有的键值
> HGETALL uid:1
1) "name"
2) "qian"
3) "age"
4) "23"

2、购物车
以用户 id 为 key,商品 id 为 field,商品数量为 value

# 添加商品:
HSET cart:user1 iphone1 1
# 添加数量:
HINCRBY cart:user1 iphone1 1
# 商品总数:
HLEN cart:user1
# 删除商品:
HDEL cart:user1 iphone1
# 获取购物车所有商品:
HGETALL cart:user1

在回显商品具体信息的时候,还需要拿着商品 id 查询一次数据库,获取完整的商品的信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/522032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

原生js手动实现一个多级菜单效果(高度可过渡变化)

文章目录 学习链接效果图代码要点 学习链接 vue实现折叠展开收缩动画 - 自己的链接 elment-ui/plus不定高度容器收缩折叠动画组件 - 自己的链接 Vue transition 折叠类动画自动获取隐藏层高度以及手风琴效果实现 vue transition动画钩子- vue官网 vue transition 过渡动画…

vue基础入门

1. vue简介 1.1 什么是vue 官方概念&#xff1a;Vue&#xff08;读音/vju:/&#xff0c;类似于view&#xff09;是一套用于构建用户界面的前端框架 1.2 vue 的特性 vue 框架的特性&#xff0c;主要体现在如下两方面&#xff1a; ① 数据驱动视图 ② 双向数据绑定 数据驱动…

IMS补充业务场景介绍

呼叫保持流程 通话主动Hold的一方,发INVITE消息,媒体流从sendrecv变为sendonly,对方返回200 ok,媒体流从sendrecv变为recvonly,双方ACK后,进入呼叫保持状态,没有通话的RTP包。 大致流程如下 UE A发送INVITE(Sendonly)到网络 网络发送INVITE(Sendonly)到UE B UE发…

Linux文件属性修改

关于我们的文件属性如何修改呢&#xff1f; 我们今天来看一下 chmod chmod u(拥有者)/g(所属组)/o(其他人)(-)r/w/x(t) 文件名 就是这样&#xff0c;我们演示几个 我们想给拥有者去掉file1的读权限 我们file1的拥有者已经没有读权限了&#xff0c;那么我们还想加回来呢…

asp.net+C#基于web的旅游网站自驾游网站

&#xff08;1&#xff09;登录注册模块&#xff1a;输入账号密码&#xff0c;数据库进行验证&#xff0c;正确通过后&#xff0c;根据不同的账户信息&#xff0c;不同角色&#xff0c;获取不同的功能。 &#xff08;2&#xff09;自驾游模块&#xff1a;此模块可以分享自己自…

《计算机网络—自顶向下方法》 第五章Wireshark实验:UDP 协议分析

用户数据报(UDP)协议是运输层提供的一种最低限度的复用/分解服务&#xff0c;可以在网络层和正确的用户即进程间传输数据。UDP 是一种不提供不必要服务的轻量级运输协议&#xff0c;除了复用/分用功能和简单的差错检测之外&#xff0c;几乎就是 IP 协议了&#xff0c;也可以说它…

Python操作Redis常见类型详解

1、windows 上安装 Redis 便于测试&#xff0c;笔者在 windows 上安装 Redis Redis 官方不建议在 windows 下使用 Redis&#xff0c;所以官网没有 windows 版本可以下载。微软团队维护了开源的 windows 版本&#xff0c;对于普通测试使用足够了。 1.1、安装包方式安装 Redis…

万字收藏:《2023网络工程师年度必看书单》

晚上好&#xff0c;我是老杨。 这周是总结周&#xff0c;更新的第三篇内容&#xff0c;还是关于总结的。很多人让我推荐网工适合看的书&#xff0c;其实我推荐过好多次了。 趁着年底&#xff0c;一起把我认为网工适合看的、推荐你看的、值得看的书整理一下&#xff0c;供新老…

视觉SLAM ch13 设计SLAM系统

目录 一、SLAM系统 二、工程框架 三、框架流程 四、具体实现 五、VO整体流程 六、显示整体建图效果 一、SLAM系统 实现一个精简版的双目视觉里程计&#xff0c;前端使用光流法&#xff0c;局部使用局部BA优化。 二、工程框架 app中 run_kitti_stereo.cpp是代码的运行入口…

国内免费可用 ChatGPT 网页版

ChatGPT是一个神奇的机器人&#xff0c;它可以回答任何问题&#xff0c;解决任何问题。它的名字来源于“Chat”和“GPT”&#xff0c;前者代表聊天&#xff0c;后者代表生成预测文本。它被设计成一个智能助手&#xff0c;可以帮助人们解决各种问题。 有一天&#xff0c;一个名…

【Python 爬虫之requests库】零基础也能轻松掌握的学习路线与参考资料

文章目录 一、概述二、Requests 库基本用法三、爬虫中的优秀实践四、参考资料 一、概述 Python 爬虫中&#xff0c;常用来请求网页的库有 urllib、urllib2、httplib等&#xff0c;但是这些库用起来比较麻烦&#xff0c;需要写很多代码。Requests 库正是为了解决这个问题而生的…

Flask轻松构建钉钉接口模版,实现自动化流程优化

项目背景 随着钉钉应用的不断普及和企业数字化程度的提高&#xff0c;越来越多的企业需要开发钉钉接口来完成内部业务流程的自动化和优化。而Flask框架&#xff0c;则是一个轻量级的Python web框架&#xff0c;具有快速开发和灵活性的优势&#xff0c;是钉钉接口开发的理想选择…

python去重列表中相同的字典元素

python去重列表中相同的字典元素 文章目录 python去重列表中相同的字典元素一.知识点二.代码|代码1|问题 |代码2 三.分析总结1、分析2、总结 四.后续代码知识点代码流程问题总结总结 一.知识点 ​ data_list [{“a”: 1, “b”: 2}, {“a”: 2, “b”: 3}, {“a”: 1, “b”:…

华为OD机试真题 Java 实现【相同数字的积木游戏1】【2023Q2 100分】

一、题目描述 小华和小薇一起通过玩积木游戏学习数学。 他们有很多积木&#xff0c;每个积木块上都有一个数字&#xff0c;积木块上的数字可能相同。 小华随机拿一些积木挨着排成一排&#xff0c;请小薇找到这排积木中数字相同且所处位置最远的2块积木块&#xff0c;计算他们…

【C++】——string的模拟实现

前言&#xff1a; 在之前的学习中&#xff0c;我们已经对string类进行了简单的介绍&#xff0c;大家只要能够正常使用即可。但是在面试中&#xff0c;面试官总喜欢让学生自己 来模拟实现string类&#xff0c;最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数…

lightroom磨皮滤镜中文插件Portraiture4最新版本

哈喽&#xff01;小伙伴们&#xff01;整个摄影后期行业都在用Portraiture&#xff0c;这是一个被奉为高级磨皮面板&#xff0c;修图神器、修图的的扩展面板&#xff01;Portraiture这款磨皮插件终于更新啦&#xff01;最近推出了Portraiture4.03版本,新版本光影处理更强大&…

《编程思维与实践》1066.最小不重复数

《编程思维与实践》1066.最小不重复数 题目 思路 一般在oj上循环 2 ⋅ 1 0 9 2\cdot 10^9 2⋅109次以上就会超时,所以由于这题的数据A可以很大,直接循环加一再判断会超时. 优化:首先可以明确要想使不重复数尽可能小,则高位数字应该尽可能小, 即先找到最靠前的两个重复数字,然后…

【Vector VN1630/40 I/O应用】-1-简易示波器

案例背景(共13页精简)&#xff1a;该篇博客将告诉您&#xff1a; Vector VN1630A&#xff0c;VN1640A&#xff0c;VH6501 I/O的使用&#xff1b;将Vector VN1630A/VN1640A CAN/LIN Interface的I/O接口充当一个简易的“示波器”使用&#xff1b;观察“CAN唤醒”工作的ECU控制器…

关于C语言的杂记4

文章目录 数据与程序结构C语言的编程机制#include <>和#include ""的区别形式参数和实际参数值传递地址传递 素数 文章内容摘自或加工于C技能树一些大佬的博文 数据与程序结构 阅读完C的编程机制和函数的声明和定义后的一些启发。——预处理 C语言的编程机制 …

dubbo技术

1、Dubbo的前世今生 2011年10月27日&#xff0c;阿里巴巴开源了自己的SOA服务化治理方案的核心框架Dubbo&#xff0c;服务治理和SOA的设计理念开始逐渐在国内软件行业中落地&#xff0c;并被广泛应用。 早期版本的dubbo遵循SOA的思想&#xff0c;是面向服务架构的重要组件。 …