事务与 Lua 脚本
掌握 Redis 事务的使用与局限
掌握 Lua 脚本的编写与执行
理解原子性保障与适用场景
核心讲解
(1)Redis 事务
把多个命令打包,顺序执行,执行期间不被其他命令打断。
开启:
MULTI入队:命令都加入队列,不立即执行
执行:
EXEC,一次性执行所有命令取消:
DISCARD,放弃事务
注意:Redis 事务不是传统的原子事务,运行中某个命令错了,后面的还会执行,不会回滚!只是一起执行,不被打断。
(2)Lua 脚本
Redis 支持执行 Lua 脚本,整个脚本是原子执行的,中间不会插入其他命令,比事务更强大,可以写逻辑。
执行:
EVAL "脚本" key数量 key列表 参数列表脚本里调用 Redis 命令:
redis.call('命令', key, 参数...)优势:原子、减少网络开销、复杂逻辑
场景:复杂原子操作、分布式锁、库存扣减
操作示例
# ===== 事务示例 =====
MULTI
SET a 1
SET b 2
INCR a
EXEC
# 一次性执行所有命令,返回每个命令的结果
# 取消事务
MULTI
SET c 3
DISCARD
# 取消,不执行
# ===== Lua脚本 =====
# 简单脚本:设置并返回值
EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 test_key hello
# KEYS[1]是第一个key,ARGV[1]是第一个参数
# 原子扣减库存,判断库存
EVAL "
local stock = tonumber(redis.call('GET', KEYS[1]))
if stock and stock >= tonumber(ARGV[1]) then
redis.call('DECRBY', KEYS[1], ARGV[1])
return 1
else
return 0
end
" 1 product:1:stock 1
# 库存够扣减返回1,不够返回0,原子操作
# ===== 脚本缓存 =====
# 加载脚本,返回SHA
SCRIPT LOAD "return redis.call('PING')"
# 返回sha值
# 通过SHA调用,不用每次传脚本
EVALSHA 脚本sha 0
常见误区
Redis 事务有回滚:没有!命令语法错了 EXEC 才会全失败,运行时错误不会回滚,后面的继续
Lua 脚本能写很长逻辑:脚本不能太长,执行时间太长会阻塞 Redis,尽量短小
KEYS 和 ARGV 分不清:KEYS 传 Redis 的 key,ARGV 传业务参数,脚本里对应 KEYS 和 ARGV 数组
事务和 Lua 一样:Lua 功能强太多,有逻辑、有判断,原子性一样,推荐复杂逻辑用 Lua
课后练习
用事务打包执行 3 条命令
写一个 Lua 脚本,实现原子点赞,返回最新点赞数
写一个 Lua 脚本,实现简单的分布式锁
思考:Redis 事务和 Lua 脚本的区别是什么?

