个人技术分享

大家好,我是白晨,一个不是很能熬夜,但是也想日更的人。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!💪💪💪

在这里插入图片描述

Redis数据类型之String


介绍


String是Redis最基本的类型,一个key对应一个value。key为标识符,valuekey对应的值。

String是二进制安全的,意思是Redis的String可以包含任何数据,比如jpg图片或者序列化的对象 。

String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M。

image-20240514151952654


常用指令


设置/获取单个键值


# 设置指定 key 的值
127.0.0.1:6379> set name baichen
OK
# 获取指定 key 的值
127.0.0.1:6379> get name
"baichen"

设置/获取多个键值


# 同时设置一个或多个 key-value 对
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
# 获取所有(一个或多个)给定 key 的值
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"

设置/获取指定区域范围内的值


# 返回 key 中字符串值从下标 start 到下标 end 的子字符串
127.0.0.1:6379> getrange name 0 -1 # 0 -1表示从字符串开头到字符串结尾
"baichen12345"
127.0.0.1:6379> getrange name 7 -1
"12345"
127.0.0.1:6379> getrange name 0 6
"baichen"
# 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
127.0.0.1:6379> setrange name 7 6789 # 从offset=7的位置设置字符串6789
(integer) 12
127.0.0.1:6379> get name
"baichen67895"

数值增减


127.0.0.1:6379> set number 1
OK
# 将 key 中储存的数字值增一
127.0.0.1:6379> incr number
(integer) 2
127.0.0.1:6379> get number
"2"
# 将 key 所储存的值加上给定的增量值(increment)
127.0.0.1:6379> incrby number 3
(integer) 5
127.0.0.1:6379> get number
"5"
# 将 key 中储存的数字值减一
127.0.0.1:6379> decr number
(integer) 4
127.0.0.1:6379> get number
"4"
# key 所储存的值减去给定的减量值(decrement)
127.0.0.1:6379> decrby number 3
(integer) 1
127.0.0.1:6379> get number
"1"

获取字符串长度


127.0.0.1:6379> set name baichen
OK
# 返回 key 所储存的字符串值的长度
127.0.0.1:6379> strlen name
(integer) 7

内容追加


# 如果 key 已经存在并且是一个字符串,APPEND 命令将 value 追加到 key 原来的值的末尾
127.0.0.1:6379> set name baichen
OK
127.0.0.1:6379> append name 12345
(integer) 12
127.0.0.1:6379> get name
"baichen12345"

set命令的更多扩展


setex
# 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)
127.0.0.1:6379> setex k1 10 v1 # 设置 10 秒过期时间
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> ttl k1 # 获取剩余过期时间
(integer) 5
127.0.0.1:6379> ttl k1
(integer) -2
127.0.0.1:6379> get k1 # k1 已过期
(nil)
setnx
# 只有在 key 不存在时设置 key 的值
127.0.0.1:6379> setnx k2 v2
(integer) 0
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> setnx k2 baichen
(integer) 0
127.0.0.1:6379> get k2 # 值没有发生变化
"v2"
[EX seconds]
# 设置 key 的生存时间为指定的秒数,等价于setex
127.0.0.1:6379> set k1 v1 ex 10
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> ttl k1
(integer) 5
127.0.0.1:6379> ttl k1
(integer) -2
127.0.0.1:6379> get k1
(nil)
[NX]
# 只有在 key 不存在时,才设置(SET if Not eXists),等价于setnx
127.0.0.1:6379> set k1 v1 nx
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> set k1 baichen nx
(nil)
127.0.0.1:6379> get k1
"v1"
[XX]
# 只有在 key 已经存在时,才设置(SET if eXists)
127.0.0.1:6379> set k1 v1 xx # k1 没有设置时,设置不了 k1 的值
(nil)
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k1 baichen xx # 只有 k1 有值时,才能设置value
OK
127.0.0.1:6379> get k1
"baichen"
[KEEPTTL]
# 在使用 NX 或 XX 选项时,保持原有的过期时间(Keep Time To Live)
127.0.0.1:6379> set k1 v1 ex 20
OK
127.0.0.1:6379> ttl k1
(integer) 19
127.0.0.1:6379> set k1 baichen keepttl
OK
127.0.0.1:6379> get k1
"baichen"
127.0.0.1:6379> ttl k1 # 继承了旧 k1 的过期时间,如果不使用keepttl参数,过期时间会按照新 k1 的设置重置
(integer) 9
127.0.0.1:6379> ttl k1
(integer) -2

getset


# 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> getset k1 baichen
"v1"
127.0.0.1:6379> get k1
"baichen"

常用指令汇总


String常用命令汇总

命令 描述
SET key value 设置指定 key 的值
GET key 获取指定 key 的值
GETRANGE key start end 返回 key 中字符串值从下标 start 到下标 end 的子字符串
GETSET key value 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
GETBIT key offset 对 key 所储存的字符串值,获取指定偏移量上的位(bit)
MGET key1 [key2..] 获取所有(一个或多个)给定 key 的值
SETBIT key offset value 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)
SETEX key seconds value 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)
SETNX key value 只有在 key 不存在时设置 key 的值
SETRANGE key offset value 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
STRLEN key 返回 key 所储存的字符串值的长度
MSET key value [key value ...] 同时设置一个或多个 key-value 对
MSETNX key value [key value ...] 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
PSETEX key milliseconds value 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位
INCR key 将 key 中储存的数字值增一
INCRBY key increment 将 key 所储存的值加上给定的增量值(increment)
INCRBYFLOAT key increment 将 key 储存的值加上给定的浮点增量值(increment)
DECR key 将 key 中储存的数字值减一
DECRBY key decrement key 所储存的值减去给定的减量值(decrement)
APPEND key value 如果 key 已经存在并且是一个字符串,APPEND 命令将 value 追加到 key 原来的值的末尾

set命令参数汇总

命令全称及参数 描述
SET key value 设置指定 key 的值
[NX] 只有在 key 不存在时,才设置(SET if Not eXists)
[XX] 只有在 key 已经存在时,才设置(SET if eXists)
[EX seconds] 设置 key 的生存时间为指定的秒数
[PX milliseconds] 设置 key 的生存时间为指定的毫秒数
[EXAT unix-time-seconds] 设置 key 从给定的 Unix 时间戳开始生存,单位为秒
[PXAT unix-time-milliseconds] 设置 key 从给定的 Unix 时间戳开始生存,单位为毫秒
[KEEPTTL] 在使用 NX 或 XX 选项时,保持原有的过期时间(Keep Time To Live)

应用场景


缓存


在用 Redis 作为缓存时,String 类型通常用于存储会频繁被读取但更新不是非常频繁的数据。

比如,

  1. 缓存用户会话
    • 当用户登录系统后,其会话信息可以存储在 Redis 中,以便于快速验证用户状态。
  2. 缓存网页内容
    • 对于不经常变动的网页内容,如网站的静态页面,可以缓存在 Redis 中以减少数据库的访问次数。
# 将用户会话信息缓存起来
127.0.0.1:6379> SET session:12345 '{"username":"kimi","permissions":"admin"}' EX 3600
OK
# 读取缓存的用户会话信息
127.0.0.1:6379> GET session:12345
"{\"username\":\"kimi\",\"permissions\":\"admin\"}"
# 缓存某个商品的详情页内容
127.0.0.1:6379> SET product:54321 "<html>商品详情页的内容</html>" EX 300
OK
# 读取缓存的商品详情页内容
127.0.0.1:6379> GET product:54321
"<html>商品详情页的内容</html>"

计数器


Redis 的 String 类型除了可以存储简单的字符串外,还可以用作计数器。这是因为 Redis 的 String 在内部是二进制安全的,所以不仅可以存储文本数据,还可以存储任何格式的二进制数据,包括整数。

比如,统计某个帖子的点赞数:

# 假设有一个帖子的ID为1234,初始化点赞计数器
127.0.0.1:6379> SET post:likes:1234 0
OK
# 用户A点赞,增加点赞数
127.0.0.1:6379> INCR post:likes:1234
(integer) 1
# 用户B点赞,继续增加点赞数
127.0.0.1:6379> INCR post:likes:1234
(integer) 2
# 获取当前的点赞数以展示
127.0.0.1:6379> GET post:likes:1234
"2"
# 用户A取消点赞,减少点赞数
127.0.0.1:6379> DECR post:likes:1234
(integer) 1
# 如果需要给点赞数增加一个特定的数值,比如一次性增加10个赞
127.0.0.1:6379> INCRBY post:likes:1234 10
(integer) 11
# 再次获取当前的点赞数
127.0.0.1:6379> GET post:likes:1234
"11"

分布式锁


Redis 的 String 类型可以被用作实现分布式锁,这在分布式系统中用于确保资源在多个进程或多个服务器之间被同步访问。分布式锁的关键在于能够安全地获取和释放锁,并且能够在持有锁的进程崩溃时能够安全地释放锁。

image-20240516215028531

以下是使用 Redis String 类型实现分布式锁的一个基本示例:

  1. 获取锁: 使用 SET 命令结合 NX(Not eXists)和 PX(毫秒为单位设置超时时间)选项来获取锁。
  2. 释放锁: 执行完临界区的操作后,通过 DEL 命令删除锁。
  3. 锁超时: 使用 SET 命令设置锁的同时,可以设置一个过期时间,这样即使持有锁的进程崩溃,锁也会在一定时间后自动释放。
  4. 锁续约: 如果锁持有者仍然需要这个锁,它可以在锁即将过期前续约。
# 尝试获取锁,'lock:key' 是锁的键,'lockvalue' 是锁的值,用于后续识别和释放锁,10000 是锁的超时时间,单位为毫秒
SET lock:key lockvalue NX PX 10000

# 如果 SET 命令成功,那么获取到了锁,可以执行临界区的代码
# 执行临界区操作...

# 释放锁,通过 DEL 命令删除锁
DEL lock:key

在实际应用中,为了确保锁的安全性,还需要考虑以下几个因素:

  • 锁超时:如果进程在持有锁期间崩溃,需要锁能够自动释放。这可以通过 SET 命令的 PX 选项实现。
  • 锁续约:如果临界区的操作还没有完成,但是锁快要过期,持有锁的进程应该能够续约这个锁。
  • 锁识别:在释放锁时,需要确保是同一个进程释放了锁。这可以通过检查锁的值(lockvalue)来实现。
  • 避免锁的错位:使用 GETSET 命令来原子地替换锁的值,如果当前锁的值与预期的锁值匹配,则可以安全地删除锁。
  • 原子性:使用lua脚本可以用来确保一系列命令的原子性执行。

分布式锁的请求流程如下图所示:

image-20240516215137308

用Redis实现分布式锁有以下几种形式:

image-20240516213624333

一个实现良好的分布式锁流程图如下:

image-20240516214348334


Session共享


在开发后台管理系统或任何Web应用程序时,Session通常用于跟踪用户的登录状态和会话信息。在传统的单体应用架构中,Session信息存储在服务器的内存中,与用户的会话直接关联。这种模式下,用户的所有请求通常都会发送到同一个服务器,因此服务器能够识别并维护用户的会话状态。

然而,在分布式系统中,应用被部署在多个服务器上,并且用户的请求可能会被负载均衡器随机分配到不同的服务器。这种架构下,每个服务器都是独立的,并且可能没有其他服务器上的Session信息。这就导致了一个问题:如果用户的Session信息存储在特定的服务器上,当用户下一次请求被分配到不同的服务器时,该服务器将无法识别用户的会话,从而导致用户需要重新登录。

为了解决这个问题,可以采用Session共享策略

  • Session共享策略

通过某种机制,如使用一个共享的Session存储(例如Redis、Memcached等),使得所有服务器都能够访问相同的Session信息。这样,无论用户的请求被分配到哪台服务器,服务器都能够识别用户的会话状态。

image-20240516220857800


总结


特性

  • String是Redis中最基本的数据类型,采用key-value形式存储。
  • 它是二进制安全的,可以存储任何类型的数据,如图片或序列化的对象。
  • 一个String类型的value最多可以存储512M的数据。

常用指令

  • SET / GET:设置和获取单个键值。
  • MSET / MGET:同时设置或获取多个键值。
  • GETRANGE / SETRANGE:获取或设置字符串的指定区域。
  • INCR / DECR:数值增减操作。
  • STRLEN:获取字符串长度。
  • APPEND:追加内容到现有字符串。
  • SETEX / PSETEX:设置键值并指定过期时间(秒/毫秒)。
  • SETNX:仅当键不存在时设置值。
  • GETSET:设置新值并获取旧值。
  • 其他位操作指令:SETBIT / GETBIT

set命令的扩展参数

  • NX:仅当键不存在时设置。
  • XX:仅当键已存在时设置。
  • EX / PX:设置键的过期时间(秒/毫秒)。
  • KEEPTTL:保持原有的过期时间。

应用场景

  1. 缓存:用于存储频繁读取且更新不频繁的数据,如用户会话和网页内容。
  2. 计数器:用于统计数据,如帖子的点赞数。
  3. 分布式锁:用于在分布式系统中同步资源访问,确保安全地获取和释放锁。
  4. Session共享:在分布式Web应用中共享Session信息,以维持用户状态。

如果讲解有不对之处还请指正,我会尽快修改,多谢大家的包容。

如果大家喜欢这个系列,还请大家多多支持啦😋!

如果这篇文章有帮到你,还请给我一个大拇指 👍和小星星 ⭐️支持一下白晨吧!喜欢白晨【Redis】系列的话,不如关注👀白晨,以便看到最新更新哟!!!

我是不太能熬夜的白晨,我们下篇文章见。