当前位置: 首页 > news >正文

为什么Redis的操作是原子性的?如何保证原子性的?

对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。
Redis的操作之所以是原子性的,是因为Redis是单线程的。
Redis本身提供的所有API都是原子操作,Redis中的事务其实是要保证批量操作的原子性。
多个命令在并发中也是原子性的吗?
不一定, 将get和set改成单命令操作,incr 。使用Redis的事务,或者使用Redis+Lua==的方式实现

为什么Redis的操作是原子性的?如何保证原子性的?

一、Redis 操作是原子性的原因:

Redis 的单个命令操作是原子性的,这主要归功于 Redis 是单线程模型(这里主要指 Redis 6.0 之前的版本,以及主线程处理命令的部分;Redis 6.0 之后虽然引入了多线程 I/O,但命令的执行仍然是单线程的)。

1. 单线程模型保障原子性
  • Redis 服务端的核心命令处理逻辑运行在一个主线程中(即 Redis 的“主线程”或“事件循环线程”),这意味着同一时间只有一个命令在执行
  • 由于同一时刻只有一个操作在执行,因此不存在多个命令同时修改同一份数据的情况,也就不会发生并发冲突
  • 所以,每一个单独的 Redis 命令,比如 SET、GET、INCR 等,都是不可再分的、一次性完成的操作,执行要么成功,要么失败,不会执行到一半。这就符合原子性的定义。

结论:Redis 的单个命令是原子性的,这是由 Redis 的单线程执行模型所天然保证的。


二、Redis 提供的 API 基本都是原子操作

Redis 为开发者提供了很多常见的原子操作,例如:

  • INCR:对某个 key 的值原子地加 1,即使多个客户端同时执行 INCR,也不用担心并发问题。
  • SETNX(SET if Not eXists):也是原子操作,常用于实现分布式锁。
  • HINCRBYLPUSHSADD 等很多操作也是原子的。

这些命令在执行时不会被其他命令打断,保证了操作的完整性。


三、Redis 事务是否能保证原子性?

Redis 提供了 事务机制(MULTI / EXEC / DISCARD / WATCH),但它跟传统数据库的事务(如 ACID 中的原子性)不完全一样

Redis 事务的特点:
  • 事务中的多个命令会按顺序执行,不会被其他客户端的命令插入打断
  • 但是!如果事务中的某一条命令执行失败(比如对字符串类型执行 INCR),其他命令仍然会继续执行不会回滚
  • Redis 事务只能保证:事务内的命令会连续、不被打扰地执行,但不提供回滚机制,也不保证所有命令都“成功”

✅ 所以,Redis 事务可以看作是一种批量命令的有序执行机制,它在一定程度上保证了批量操作的“隔离性”与“连续性”,但并不严格保证“原子性”(即全部成功或全部失败)。


四、多个命令并发时是否原子?

不一定!

如果你在应用层连续发送多个 Redis 命令,比如先 GET 再 SET,这在并发场景下就不是原子操作,中间可能被其他客户端的命令插入,导致数据不一致。

🔴 举个例子:实现一个计数器自增逻辑,如果你用 GET 获取值,然后在代码里 +1,再用 SET 设置回去,这个过程就不是原子的,在高并发下会出现丢失更新的问题。


五、如何保证多个命令的原子性?

如果你的业务逻辑需要多个命令组合在一起作为一个完整的、不可分割的操作(即多个命令要原子执行),可以采用以下方案:


方案 1:使用 Redis 提供的原子命令(推荐能满足需求时优先使用)

比如:

  • 不要用 GET + SET 来实现自增,而是直接使用 INCR
  • 使用 SETNX 实现分布式锁。
  • 使用 HINCRBY 对 Hash 中的字段原子递增等。

优点:简单高效,性能好,无需额外逻辑。


方案 2:使用 Redis 事务(MULTI / EXEC)

把多个命令放到 MULTI 和 EXEC 之间,让 Redis 按顺序执行它们,且不会被其他命令插入。

MULTI
INCR counter
EXPIRE counter 60
EXEC

⚠️ 但如前所述,事务不提供回滚功能,如果其中某条命令出错,其他命令依然会执行。


方案 3:使用 Lua 脚本(强烈推荐)

Redis 支持通过 Lua 脚本将多个命令封装在一起,然后一次性、原子性地执行整个脚本

🔹 Lua 脚本在 Redis 中的执行是 单线程、原子的,脚本中的所有命令要么全部执行,要么全部不执行,不会被其他客户端的命令打断。

🔹 示例:使用 Lua 脚本实现“先检查再设置”(类似 CAS 操作)

-- 伪代码示例:只有当 key 的值为 expected 时,才设置为 new_value
local current = redis.call('GET', KEYS[1])
if current == ARGV[1] thenreturn redis.call('SET', KEYS[1], ARGV[2])
elsereturn 0
end

调用方式:

EVAL "..." 1 mykey expected_value new_value

优点:灵活、强大,可以实现任意复杂的原子逻辑,是 Redis 推荐的方式之一。


总结

问题说明
Redis 单个命令是否原子?✅ 是的,比如 INCR、SET 等,因为 Redis 是单线程执行命令,天然保证原子性。
Redis 多个命令并发时是否原子?❌ 不一定,比如 GET + SET 不是原子的,需用原子命令、事务或 Lua 脚本。
Redis 事务是否能保证原子性?⚠️ 事务能保证多个命令连续执行,但不提供回滚,不保证全部成功或失败,不是严格意义上的原子性。
如何保证多个命令的原子性?✅ 推荐使用 原子命令(如 INCR)、Lua 脚本,它们能真正实现多个命令的“原子执行”。

💡 扩展知识(难度+)

  • Redis 6.0 之后引入了多线程 I/O,但命令执行仍然是单线程的,所以不影响原子性。
  • Redis Cluster 模式下,原子性仍然由各个节点单线程保证,但跨节点的操作无法保证原子性。
  • 分布式锁、秒杀、计数器等场景,通常需要依赖 INCR、SETNX 或 Lua 脚本来保证原子性。

http://www.dtcms.com/a/569503.html

相关文章:

  • C++17 异构(tuple)与多模态数据结构(variant)
  • 【SpringBoot】玩转 Spring Boot 日志:级别划分、持久化、格式配置及 Lombok 简化使用
  • 火山引擎数智平台VeDI重磅发布“AI助手”:以大模型驱动数据飞轮,赋能非技术人员高效“看数、用数”
  • 前言:可视化搭建诞生背景 什么是可视化
  • 个人博客网站怎么注册网站怎么做会员系统
  • 山东省建设厅招标网站首页c可以做网站吗
  • 【Solidity 从入门到精通】第3章 Solidity 基础语法详解
  • 【仓颉纪元】仓颉实战深度复盘:21 天打造鸿蒙天气应用
  • Idea(2023版)使用Svn
  • windows SVN 修改提交作者、提交注释、提交日期
  • 网站空间购买哪家好wordpress 字体颜色
  • 网站定制哪个好建筑模板厚度一般是多少
  • 专门型网站wordpress无法设置语言包
  • 在windows下使用vscode进行cuda编程
  • 复变函数与积分变换 第一章——复数与复变函数
  • 告别预训练:清华大学πRL实现机器人“在实践中进化”的通用解决方案
  • U8/发票请款未发现符合条件的单据
  • 本地赣州网站建设ui界面设计案例分析
  • 【生成模型(一)】Score-Based Generative Models
  • Erasmus Glioma Database (EGD)数据集下载
  • FeatEnHancer:在低光视觉下增强目标检测及其他任务的分层特征
  • 网站建设流程及构架郑州网站建设推广渠道
  • QuickData
  • 和网站开发公司如何签合同world做网站怎么做连接
  • AIGC中stable-diffusion安装部署
  • 飞腾D3000自带10G网卡调试
  • git简介和常用方法
  • Java114 LeeCode 翻转二叉树
  • 网站建设优化托管如何给网站添加cnzz
  • 免费物流公司网站模板小程序定制开发团队