1.如何实现redis 原子性?
Redis 提供了两种主要机制来保证原子性:
-
Lua 脚本(推荐方式):
-
原理: Redis 会将整个 Lua 脚本作为一个整体执行,中间不会被其他命令插入。
-
优势: 这是目前实现复杂逻辑原子性的最成熟方案(例如实现分布式锁的核心逻辑)。
-
注意: 脚本执行时间不能过长,否则会阻塞主线程。
-
-
事务 (
MULTI/EXEC):-
原理: 使用
MULTI开启事务,将命令入队,最后用EXEC一次性执行。 -
致命缺陷(面试必问): Redis 事务不支持回滚(Rollback)。
-
如果事务中有语法错误(编译时错误),整个事务会被放弃。
-
但如果事务中有运行时错误(比如对 String 类型做 List 操作),出错的命令会失败,但其他命令依然会成功执行。
-
-
结论: 它是“伪事务”,无法保证 ACID 中的 A(原子性 - 要么全做要么全不做),因此在现代开发中不如 Lua 脚本常用。
-
一句话总结: “简单逻辑用单条命令(本身原子),复杂逻辑用Lua 脚本(确保整体原子),尽量少用事务(因为不支持回滚)。”
2.除了lua有没有什么也能保证redis的原子性?
有,主要包含以下 2 种方案(重点是 Redis 7.0 新特性):
-
Redis Functions (Redis 7.0+ 新特性):
-
定义: 这可以理解为 Lua 脚本的“进化版”。它将脚本逻辑持久化存储在 Redis 服务端,不再需要每次都从客户端发送脚本代码。
-
优势: 像调用 SQL 存储过程一样调用它(使用
FCALL命令),不仅节省了带宽,还解决了 Lua 脚本丢失或管理混乱的问题,同样严格保证原子性。
-
-
单条命令 (Native Commands):
-
原理: Redis 的核心命令处理是单线程的,所以任何单条核心命令(如
INCR,DECR,SETNX,MSET)本身就是绝对原子的。 -
应用: 对于简单的计数或状态切换,直接用单条命令即可,不需要搞复杂的脚本。
-
补充说明(面试防坑): “虽然 事务 (MULTI/EXEC) 也可以打包执行命令,但因为它不支持回滚(报错后继续执行后续命令),所以在严格要求原子性的复杂业务场景下(如转账),通常不推荐作为首选方案,而是优先使用 Lua 脚本 或 Redis Functions。”