【Redis】事务与Lua脚本Day7(2026年)

发布时间:2026/6/1 14:29:15

【Redis】事务与Lua脚本Day7(2026年) 写在前面Redis的事务机制与关系型数据库有很大不同它没有完整的ACID特性这让很多开发者感到困惑。同时Lua脚本作为Redis的原子执行能力在复杂业务场景中发挥着重要作用。今天我们深入探讨Redis事务和Lua脚本的原理与应用。文章目录写在前面一、Redis事务基础1.1 什么是Redis事务1.2 事务相关命令1.3 事务基本使用二、WATCH命令详解2.1 WATCH的作用2.2 WATCH使用示例2.3 WATCH实现乐观锁三、Redis事务的ACID分析3.1 原子性Atomicity3.2 一致性Consistency3.3 隔离性Isolation3.4 持久性DurabilityACID对比表四、Lua脚本详解4.1 为什么需要Lua脚本4.2 Lua脚本基本使用4.3 常用Lua脚本示例4.4 Lua脚本注意事项五、事务 vs Lua脚本对比六、踩坑提醒七、面试高频考点考点1Redis事务和MySQL事务的区别考点2Redis事务如何实现乐观锁考点3Lua脚本的优势是什么考点4如何处理Lua脚本执行超时八、参考资料九、互动话题一、Redis事务基础1.1 什么是Redis事务实际场景电商秒杀场景中需要先检查库存、再扣减库存、最后记录订单这三个操作必须作为一个整体执行否则可能出现超卖问题。Redis事务是一组命令的集合这些命令会被顺序执行执行过程中不会被其他客户端的命令打断。但需要注意的是Redis事务不支持回滚这与MySQL等关系型数据库有本质区别。1.2 事务相关命令命令说明MULTI开启事务EXEC执行事务中的所有命令DISCARD取消事务WATCH监视一个或多个key1.3 事务基本使用正常执行流程# 开启事务 MULTI # 返回QUEUED # 命令入队 SET user:1:name zhangsan QUEUED SET user:1:age 25 QUEUED INCR counter QUEUED # 执行事务 EXEC # 返回1) OK 2) OK 3) 1取消事务MULTI SET key1 value1 DISCARD # 事务取消命令不会执行二、WATCH命令详解2.1 WATCH的作用经验之谈WATCH是实现乐观锁的关键它可以让事务在执行前检查key是否被修改。WATCH命令用于监视一个或多个key如果在事务执行前这些key被其他客户端修改则事务会被拒绝执行。2.2 WATCH使用示例场景转账操作# 客户端A监视账户余额 WATCH account:balance GET account:balance # 返回100 MULTI DECRBY account:balance 50 EXEC # 如果期间没有其他客户端修改balance事务成功执行如果期间被其他客户端修改# 客户端B在客户端A执行EXEC之前 SET account:balance 200 # 客户端A执行EXEC EXEC # 返回(nil) 事务执行失败2.3 WATCH实现乐观锁┌─────────────────────────────────────────────────┐ │ 乐观锁流程 │ ├─────────────────────────────────────────────────┤ │ 1. WATCH key │ │ 2. GET key 获取当前值 │ │ 3. 计算新值 │ │ 4. MULTI │ │ 5. SET key 新值 │ │ 6. EXEC │ │ - 成功事务执行 │ │ - 失败key被修改重试整个流程 │ └─────────────────────────────────────────────────┘三、Redis事务的ACID分析踩坑提醒Redis事务不支持回滚如果事务中某条命令执行失败其他命令仍然会继续执行。3.1 原子性AtomicityRedis事务的原子性分析情况原子性说明命令入队失败满足整个事务被拒绝执行命令执行失败不满足错误命令跳过其他继续执行服务器宕机不满足已执行的命令无法回滚示例命令执行失败不影响其他命令MULTI SET key1 value1 LPUSH key1 value2 # 错误对string类型执行list操作 SET key2 value2 EXEC # 返回1) OK 2) (error) WRONGTYPE 3) OK # key1和key2都设置成功LPUSH失败3.2 一致性ConsistencyRedis事务可以保证一致性入队错误整个事务不会执行执行错误错误命令会被识别并跳过服务器宕机根据持久化配置恢复数据3.3 隔离性IsolationRedis事务的隔离性分析隔离级别是否支持说明读未提交支持事务执行前可看到其他事务未提交的数据读已提交支持单线程模型事务执行时不会被干扰可重复读不支持WATCH可以部分实现串行化支持单线程执行3.4 持久性Durability取决于持久化配置无持久化不满足持久性RDB可能丢失几分钟数据AOF(everysec)可能丢失1秒数据AOF(always)基本满足持久性ACID对比表特性Redis事务MySQL事务原子性部分无回滚完整支持一致性支持支持隔离性单线程隔离多种隔离级别持久性取决于配置支持WAL四、Lua脚本详解4.1 为什么需要Lua脚本实际场景分布式锁释放时需要先判断锁是否属于自己再执行DEL操作。如果用两个命令执行中间可能被其他客户端干扰。Redis Lua脚本的优势原子性整个脚本作为一个整体执行减少网络开销多个命令一次发送复用性脚本可以缓存重复使用灵活性实现复杂业务逻辑4.2 Lua脚本基本使用执行Lua脚本# EVAL命令 EVAL return redis.call(GET, KEYS[1]) 1 user:1:name # 使用KEYS和ARGV数组 EVAL return redis.call(SET, KEYS[1], ARGV[1]) 1 user:1:name zhangsan脚本缓存# 加载脚本返回SHA1校验和 SCRIPT LOAD return redis.call(GET, KEYS[1]) # 返回e465c6bf...SHA1值 # 使用SHA1执行脚本 EVALSHA e465c6bf... 1 user:1:name4.3 常用Lua脚本示例1. 分布式锁释放-- unlock.luaifredis.call(GET,KEYS[1])ARGV[1]thenreturnredis.call(DEL,KEYS[1])elsereturn0end# 执行redis-cli--evalunlock.lua lock_key , my_unique_value2. 限流脚本-- rate_limit.lualocalkeyKEYS[1]locallimittonumber(ARGV[1])localwindowtonumber(ARGV[2])localcurrentredis.call(GET,key)ifcurrentandtonumber(current)limitthenreturn0-- 超过限制endredis.call(INCR,key)iftonumber(current)0thenredis.call(EXPIRE,key,window)endreturn1-- 允许访问3. 库存扣减防超卖-- deduct_stock.lualocalstocktonumber(redis.call(GET,KEYS[1]))ifstock0thenreturn-1-- 库存不足endredis.call(DECR,KEYS[1])returnstock-14.4 Lua脚本注意事项踩坑提醒Lua脚本执行时会阻塞Redis长时间运行的脚本会影响其他请求。注意事项问题解决方案脚本执行时间过长设置lua-time-limit默认5秒脚本过大使用SCRIPT LOAD缓存脚本随机函数问题Redis禁用了部分随机函数数据类型错误使用tonumber()、tostring()转换# redis.conf 配置 lua-time-limit 5000 # Lua脚本最大执行时间毫秒五、事务 vs Lua脚本对比对比项Redis事务Lua脚本原子性部分无回滚完整原子性复杂逻辑不支持支持条件判断、循环网络开销多次交互单次交互错误处理无法捕获可以处理错误使用场景简单批量操作复杂原子操作学习成本低中等六、踩坑提醒踩坑提醒事务不支持回滚问题MULTI SET key1 value1 INCR key1 # 对string执行INCR会失败 SET key2 value2 EXEC # key1被设置为value1INCR失败key2被设置为value2解决方案使用Lua脚本实现条件判断在应用层做数据校验踩坑提醒WATCH使用后需要UNWATCH问题WATCH监视的key在EXEC/DISCARD后自动取消但如果事务被取消后想重新使用这些key需要手动UNWATCH。WATCH key1 GET key1 # 发现值不符合预期想放弃本次操作 UNWATCH # 手动取消监视七、面试高频考点考点1Redis事务和MySQL事务的区别答案对比项Redis事务MySQL事务回滚机制不支持支持隔离级别无明确级别四种隔离级别锁机制无锁行锁、表锁等原子性部分无回滚完整支持使用场景批量命令执行数据一致性保证考点2Redis事务如何实现乐观锁答案使用WATCH命令监视key在EXEC执行前检查key是否被修改。如果被修改事务返回nil应用层可以重试。WATCH key val GET key MULTI SET key new_val EXEC # 如果key被其他客户端修改EXEC返回nil考点3Lua脚本的优势是什么答案原子性整个脚本原子执行不会被其他命令打断减少网络开销多个命令一次发送复用性脚本缓存后可重复使用灵活性支持条件判断、循环等复杂逻辑考点4如何处理Lua脚本执行超时答案设置合理的lua-time-limit配置使用SCRIPT KILL命令终止正在执行的脚本如果脚本已经执行了写操作只能使用SHUTDOWN NOSAVE强制关闭优化脚本逻辑避免长时间运行八、参考资料Redis官方文档 - TransactionsRedis Lua Scripting九、互动话题你在生产环境中使用Redis事务还是Lua脚本更多为什么如何设计一个可靠的分布式锁方案需要考虑哪些问题Lua脚本执行超时时你会如何处理欢迎在评论区分享你的经验和见解下一期预告Day8 - Redis发布订阅与消息队列敬请期待

相关新闻