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

news2024/11/28 20:35:14

认识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 查询一次数据库,获取完整的商品的信息。

List

简介
  • 增删快,提供了操作某一段元素的API
  • list类型是用来存储多个有序的字符串的,列表当中的每一个字符看做一个元素
  • 一个列表当中可以存储有一个或者多个元素,redis的list支持存储232-1个元素。
  • 可以从列表的两端进行插入(pubsh)和弹出(pop)元素,支持读取指定范围的元素集,或者读取指定下标的元素等操作。
  • 列表是一种比较灵活的链表数据结构,它可以充当队列或者栈的角色。
  • 列表是链表型的数据结构,所以它的元素是有序的,而且列表内的元素是可以重复的。意味着它可以根据链表的下标获取指定的元素和某个范围内的元素集。
底层实现

在Redis 3.2之后,List数据类型底层就只由quicklist实现了,替代了之前的双向链表和压缩列表

使用
// 将值插入到key链表的头部
127.0.0.1:6379> lpush me male
(integer) 1
127.0.0.1:6379> lpush me qian
(integer) 2
// 将值插入到key链表的尾部
127.0.0.1:6379> rpush me 23
(integer) 3
// 查看0-10范围内的元素
127.0.0.1:6379> lrange me 0 10
1) "qian"
2) "male"
3) "23"
// 通过索引获取列表中的元素,下标从零开始
127.0.0.1:6379> lindex me 2
"23"
// 弹出链表尾部元素
127.0.0.1:6379> rpop me
"23"
// 弹出链表头部元素
127.0.0.1:6379> lpop me
"qian"
127.0.0.1:6379> lrange me 0 10
1) "male"
// 通过索引更改链表的值
127.0.0.1:6379> lset me 0 qian
OK
127.0.0.1:6379> lrange me 0 10
1) "qian"
// 只保留指定区间内的元素,其余元素全部删除
127.0.0.1:6379> ltrim me 0 1
OK
127.0.0.1:6379> lrange me 0 10
1) "qian"
2) "male"
// 从一个列表弹出一个值放入另一个list中,如果没有可以弹出的元素会阻塞等待到超时或有元素
127.0.0.1:6379> lrange me 0 10
1) "qian"
127.0.0.1:6379> lpush me male
(integer) 2
127.0.0.1:6379> lrange you 0 10
(empty array)
127.0.0.1:6379> lpush you female
(integer) 1
127.0.0.1:6379> brpoplpush you me 1000
"female"
127.0.0.1:6379> lrange you 0 10
(empty array)
127.0.0.1:6379> lrange me 0 10
1) "female"
2) "male"
3) "qian"
使用场景

1、消息队列

  • 为了保证消息接受的顺序,可以使用LPUSH+RPOP/RPUSH+LPOP的命令实现消息队列。生产者向list中写入数据,多个消费者不停发调用pop命令,如果list中有消息,就返回,没有就继续循环。但是这种做法会导致消费者不停执行rpop/lpop命令,浪费CPU资源。
    redis还提供了brpop的命令,可以实现阻塞式存取,客户端在没有读到队列数据时,自动阻塞,直到有新的数据写入队列,再开始读取新数据,节省CPU开销
    brpop
  • 为了避免重复的消息,还可以在消息中添加一个全局的ID。消费者收到消息后先比较这次收到的消息ID和之前收到过的ID,如果没已经收到过了,就不再处理了。
# 添加唯一ID:20230514
lpush mq "20230514:qian:0039"
(integer) 1
  • 为了保证消息可靠性,防止接受了消息但是还没处理就发生意外导致消息丢失,可以使用brpoplpush的命令,从队列中读取消息后加入到备份list中存档,这样,如果消费者没来得及处理消息还可以去备份list中重新读取
  • 但是list中一个消息只能有一个消费者接收,也不支持消费者组,通常使用Stream类型实现mq

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

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

相关文章

企业有必要对三方应用进行安全管控吗?

什么是三方应用&#xff1f; 三方应用是指由第三方开发者创建的软件应用程序&#xff0c;与操作系统或其他主要平台的开发公司无关。这些应用程序通常被设计为在特定平台上运行&#xff0c;并且具有特定的功能或服务&#xff0c;例如社交媒体应用程序、游戏和生产力工具等。 简…

IntersectionObserver“替代”滚动条监听

概要 IntersectionObserver 接口提供了一种异步观察目标元素与其祖先元素或顶级文档视口&#xff08;viewport&#xff09;交叉状态的方法。其祖先元素或视口被称为根&#xff08;root&#xff09;。 当一个 IntersectionObserver 对象被创建时&#xff0c;其被配置为监听根中…

Blender渲染分辨率如何优化设置?这些渲染技巧你要知道!

尽管 Blender不断改进其功能&#xff0c;随着硬件的不断进步而变得越来越复杂&#xff0c;该软件最好的是允许很多人免费试用它。但即使所有人都可以访问&#xff0c;这并不意味着Blender可以克服低端GPU的局限性。 并非所有PC都是平等的&#xff0c;也不是每个3D设计师都可以使…

Aho-Corasick automaton,ac自动机实现

文章目录 写在前面算法概述trie树的构建trie树的节点结构插入P串到trie树中fail指针的创建 搜索过程测试程序 写在前面 原作者的视频讲解链接&#xff1a;[算法]轻松掌握ac自动机_哔哩哔哩_bilibili 原作者的代码实现&#xff1a;data-structure-and-algorithm/aho_corasick.c…

机器视觉表面划痕检测流程

表面缺陷检测常见的检测主要有物体表面的划痕、污渍、缺口、平面度、破损、边框对齐度、物体表面的亮度、皱纹、斑点、孔等。 表面缺陷检测设备凝聚了机器视觉领域的许多技术成果&#xff0c;吸取了许多创新的检测理念&#xff0c;可以与现有生产线无缝对接检测&#xff0c;也…

制定进度计划是成功项目管理的必由之路

项目经理王斌接到一个新项目&#xff0c;与各项目干系人没有建立有效的联系&#xff0c;他们无法了解项目进展情况。甚至连项目团队的参与人员自身对项目整体情况也没有清楚的认识&#xff0c;而只管自己那一部分&#xff0c;整个开发过程完全是一种黑盒模式&#xff0c;项目组…

电视盒子哪个好?内行盘点2023最具性价比电视盒子推荐

电视盒子跟有线机顶盒相比不用每年缴费&#xff0c;资源也更丰富&#xff0c;可下载各种APP。作为电视盒子从业人员&#xff0c;身边亲友在选购电视盒子之前会咨询我的意见&#xff0c;不懂电视盒子哪个好&#xff0c;可以看看我总结的2023最具性价比电视盒子推荐&#xff0c;非…

手慢无,阿里巴巴最新出品的高并发终极笔记到底有多强?

前几天收到一位粉丝私信&#xff0c;说的是他才一年半经验&#xff0c;去面试却被各种问到分布式&#xff0c;高并发&#xff0c;多线程之间的问题。基础层面上的是可以答上来&#xff0c;但是面试官深问的话就不会了&#xff01;被问得都怀疑现在Java招聘初级岗位到底招的是初…

MySQL-图形化界面工具 (下)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️树高千尺&#xff0c;落叶归根人生不易&…

springboot+mybatis+redis实现二级缓存

Mybatis提供了对缓存的支持&#xff0c;分为一级缓存和二级缓存&#xff0c;其查询顺序为&#xff1a;二级缓存>一级缓存->数据库&#xff0c;最原始是直接查询数据库&#xff0c;为了提高效率和节省资源&#xff0c;引入了一级缓存&#xff0c;为了进一步提高效率&#…

计算机网络(四下)——网络层

接上篇&#xff0c;这篇文章主要来写路由选择 五、路由协议 1>动态路由 1.距离向量算法&#xff08;RIP协议&#xff09;&#xff1b;适用于小型网络 1》规定&#xff1a; 1>记录跳数(Hop count)最少的路径。 2>RIP允许一条路由最多15个路由器&#xff0c;距离为…

LitCTF2023 wp re最后一道 cry misc

本来不打算放了&#xff0c;但是比赛打都打了留个纪念社工有佬&#xff0c;与我无关&#xff0c;misc只会隐写虽然我是逆向手&#xff0c;但因为队友tql&#xff0c;所以只留给我最后一道~~我的wp向来以简述思路为主&#xff0c;习惯就好 Crypto Hex&#xff1f;Hex&#xff…

【项目设计】 负载均衡在线OJ系统

&#x1f9f8;&#x1f9f8;&#x1f9f8;各位大佬大家好&#xff0c;我是猪皮兄弟&#x1f9f8;&#x1f9f8;&#x1f9f8; 文章目录 一、项目介绍项目技术栈和开发环境 二、项目的宏观结构三、compile_server模块①日志模块开发&#xff0c;Util工具类&#xff0c;供所以模…

NVIDIA再现谜之刀法,RTX 4060Ti新增16G版

随着上一代库存逐渐清理到位&#xff0c;苏妈与老黄终于要把新一代主流级显卡掏出来了。 根据外网消息&#xff0c;AMD 这边主要是 RX 7600XT 与 7600 等型号&#xff0c;发布日期定为 5 月 25 日。 AMD 保密措施做得挺到位的&#xff0c;目前除了部分厂商爆出的包装与产品图…

[MYAQL / Mariadb] 数据库学习-数据导入导出

数据库学习-数据导入导出 数据导入导出&#xff08;批量处理数据&#xff09;查看默认检索目录模糊查询&#xff1a;show variables like %XXXX%;修改检索目录路径&#xff08;&#xff01;&#xff01;文件一定要有MySQL用户的 7的RWX 权限&#xff01;&#xff09;默认的检索…

前端-02 CSS基础

1 简介 1.1 CSS语法 语法 选择器&#xff1a;HTML元素 生命块&#xff1a;用;隔开的各种声明 {a;b} 每条声明有CSS属性名称和值&#xff0c;用冒号分割{属性:值;属性:值} 案例 整块代码 <!DOCTYPE html> <html><head><style>body {background…

同一个IP可以安装配置多个SSL证书吗?

如何在同一IP地址上运行多个SSL证书? 服务器名称指示SNI&#xff0c;可以帮助您实现同一IP运行多个SSL证书&#xff0c;这样虚拟主机网站也能用上SSL证书了。 什么是SNI 服务器名称指示SNI是SSL的一个重要组成部分&#xff0c;SNI允许多个网站存在于同一个IP地址上&#xff…

CVPR目标检测经典作:HOG特征

来源&#xff1a;投稿 作者&#xff1a;小灰灰 编辑&#xff1a;学姐 HOG特征 HOG特征( Histogram of Oriented Gradients 方向梯度直方图&#xff09;是一种在图像上找到特征描述子&#xff0c;主要通过计算和统计图像局部区域的梯度方向直方图来构成特征。来源于cvpr2015 年…

Angular 学习笔记

本系列笔记主要参考&#xff1a; Angular学习视频 Angular官方文档 Angular系列笔记 特此感谢&#xff01; 目录 1.Angular 介绍2.Angular 环境搭建、创建 Angular 项目、运行 Angular 项目2.1.环境搭建2.2.创建 Angular 项目2.3.运行项目 3.Angular 目录结构分析3.1.目录结构分…

低分辨率视频可以变高分辨率吗?

近几年&#xff0c;老电影、老视频片段修复越来越常见了。很多优质的片源&#xff0c;因为年代久远&#xff0c;分辨率较低&#xff0c;画质比较差&#xff0c;通过视频超分技术&#xff0c;实现了画质增强&#xff0c;提高画质分辨率&#xff0c;视频画面变得更清晰了。 首先…