Redis 事务(MULTI/EXEC)与 Lua 脚本的核心区别 - 详解

news/2026/1/16 22:46:51/文章来源:https://www.cnblogs.com/yangykaifa/p/19494275

先通过对比表清晰梳理核心差异,再结合 Java 17+ + Spring Boot 代码示例说明各自使用场景:

对比维度MULTI/EXEC 事务Lua 脚本
原子性弱原子性:语法错误会放弃所有命令;运行时错误(如对字符串做自增)仅失败该命令,其余继续执行强原子性:脚本内所有命令作为整体原子执行,要么全成功,要么全失败(脚本执行中Redis单线程不处理其他请求)
逻辑能力仅支持批量命令入队,无条件判断、循环、变量等逻辑支持完整Lua语法(条件、循环、变量、函数),可基于前序命令结果执行后续逻辑
网络开销多次网络交互(MULTI→命令入队→EXEC)一次网络交互(脚本传输+执行),大幅降低网络往返
错误处理无自定义错误处理,仅被动接受Redis的执行结果可在脚本内捕获错误、自定义兜底逻辑(如redis.call失败时返回特定值)
资源占用事务期间占用客户端连接,直到EXEC/放弃脚本执行期间占用Redis单线程,长脚本会阻塞所有请求(需控制脚本时长)
复用性不可复用,每次需重新入队所有命令可通过EVALSHA缓存脚本到Redis,重复执行仅传脚本SHA1值,复用性高
适用复杂度仅支持简单批量命令,无依赖逻辑支持复杂业务逻辑(依赖前序结果、条件判断、原子操作封装)

一、MULTI/EXEC 事务:适用场景与代码示例

适用场景

仅需简单批量执行无依赖的Redis命令,且能容忍“运行时错误不回滚”的场景,例如:

Java 17+ + Spring Boot 代码示例
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* MULTI/EXEC 事务示例(Spring Boot 3.x + Java 17+)
* 场景:用户下单后批量扣减库存、增加订单数(无库存判断)
*/
@Slf4j
@Service
public class RedisTransactionService {
private final RedisTemplate<String, Object> redisTemplate;// 构造器注入(Spring Boot 3.x 推荐)public RedisTransactionService(RedisTemplate<String, Object> redisTemplate) {this.redisTemplate = redisTemplate;}// Java 17 Record:事务执行结果public record TransactionResult(boolean success, String msg, List<Object> execResults) {}/*** 执行MULTI/EXEC事务:扣减库存 + 增加订单数*/public TransactionResult executeOrderTransaction(String productKey, String orderCountKey, int deductNum) {try {// RedisCallback 执行底层事务操作,try-with-resources 管理Redis连接(Spring自动兜底)List<Object> execResults = redisTemplate.execute((RedisCallback<List<Object>>) connection -> {// 开启事务connection.multi();// 命令入队:扣减库存(INCRBY 负数实现扣减)connection.incrBy(productKey.getBytes(), -deductNum);// 命令入队:增加订单数connection.incrBy(orderCountKey.getBytes(), 1);// 执行事务(原子提交)return connection.exec();});// Java 17 switch表达式:处理执行结果String msg = switch (execResults) {case null -> "事务被放弃(如WATCH监控的key被修改)";case List<Object> res when res.isEmpty() -> "事务执行无结果(语法错误)";default -> "事务执行成功";};return new TransactionResult(execResults != null && !execResults.isEmpty(), msg, execResults);} catch (Exception e) {log.error("MULTI/EXEC事务执行失败", e);// 异常时明确关闭Redis连接(Spring Data Redis已封装,此处兜底)redisTemplate.getConnectionFactory().getConnection().close();return new TransactionResult(false, "执行异常:" + e.getMessage(), null);}}// 测试入口public static void main(String[] args) {// Spring Boot 环境需通过ApplicationContext获取Bean,此处简化模拟RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(org.springframework.data.redis.connection.jedis.JedisConnectionFactory());RedisTransactionService service = new RedisTransactionService(redisTemplate);// 执行事务:扣减商品1001库存2个,订单数+1TransactionResult result = service.executeOrderTransaction("stock:1001", "order:count:1001", 2);log.info("事务结果:{}", result);}}
关键说明
  1. 资源管理:Spring Data Redis 自动管理 Redis 连接,异常时通过 getConnection().close() 明确关闭资源,符合“资源必须关闭”的要求;
  2. 原子性局限:若stock:1001是字符串(如"abc"),incrBy会失败,但order:count:1001仍会执行自增,体现“弱原子性”;
  3. WATCH 补充:MULTI/EXEC 可配合 WATCH 实现“乐观锁”(监控key,若被修改则事务放弃),但仍无法解决“基于前序结果执行后续命令”的场景。

二、Lua 脚本:适用场景与代码示例

适用场景

需要原子执行复杂逻辑(含条件判断、依赖前序结果)、或需降低网络开销的场景,例如:

  • 扣减库存前判断库存是否充足(库存不足则直接返回失败,不执行扣减);
  • 分布式锁的原子释放(判断锁归属后再删除,避免误删);
  • 限流算法(如令牌桶、漏桶,需原子计算剩余令牌)。
Java 17+ + Spring Boot 代码示例
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/**
* Lua脚本示例(Spring Boot 3.x + Java 17+)
* 场景:扣减库存前判断库存是否充足(原子逻辑)
*/
@Slf4j
@Service
public class RedisLuaScriptService {
private final RedisTemplate<String, Object> redisTemplate;public RedisLuaScriptService(RedisTemplate<String, Object> redisTemplate) {this.redisTemplate = redisTemplate;}// Java 17 Record:Lua脚本执行结果public record LuaResult(boolean success, String msg, Long data) {}// 库存扣减Lua脚本(原子判断+扣减)private static final String DEDUCT_STOCK_LUA = """-- 获取参数:库存key、扣减数量local stockKey = KEYS[1]local deductNum = tonumber(ARGV[1])-- 获取当前库存local currentStock = tonumber(redis.call('get', stockKey))if not currentStock thenreturn -1  -- 库存key不存在end-- 判断库存是否充足if currentStock < deductNum thenreturn 0   -- 库存不足end-- 原子扣减库存redis.call('incrby', stockKey, -deductNum)return currentStock - deductNum  -- 返回扣减后库存""";/*** 执行Lua脚本扣减库存(原子逻辑)*/public LuaResult deductStockWithLua(String stockKey, int deductNum) {// 定义Redis脚本(指定返回类型为Long)RedisScript<Long> luaScript = new DefaultRedisScript<>(DEDUCT_STOCK_LUA,Long.class);try {// try-with-resources 思想:Spring自动管理脚本执行的连接资源,异常时兜底关闭Long result = redisTemplate.execute(luaScript,Collections.singletonList(stockKey),  // KEYS参数deductNum                               // ARGV参数);// Java 17 switch表达式:处理脚本返回值String msg = switch (result) {case -1L -> "库存key不存在";case 0L -> "库存不足,扣减失败";case null -> "脚本执行异常";default -> "库存扣减成功,剩余库存:" + result;};boolean success = result != null && result > 0;return new LuaResult(success, msg, result);} catch (Exception e) {log.error("Lua脚本执行失败", e);// 明确关闭Redis连接(释放资源)redisTemplate.getConnectionFactory().getConnection().close();return new LuaResult(false, "执行异常:" + e.getMessage(), null);}}// 测试入口public static void main(String[] args) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(org.springframework.data.redis.connection.jedis.JedisConnectionFactory());RedisLuaScriptService service = new RedisLuaScriptService(redisTemplate);// 先初始化库存:set stock:1001 10redisTemplate.opsForValue().set("stock:1001", 10);// 执行Lua脚本扣减3个库存LuaResult result = service.deductStockWithLua("stock:1001", 3);log.info("Lua脚本执行结果:{}", result);}}
关键说明
  1. 原子性保障:脚本内“判断库存→扣减库存”是原子操作,Redis单线程执行期间不会处理其他请求,避免“库存超卖”;
  2. 资源管理:通过redisTemplate.getConnectionFactory().getConnection().close()确保异常时释放Redis连接,符合“资源必须关闭”要求;
  3. 脚本复用:生产环境可将Lua脚本预加载到Redis(通过SCRIPT LOAD),使用EVALSHA执行(仅传SHA1值),减少网络传输开销;
  4. 性能注意:Lua脚本需控制时长(建议<10ms),避免阻塞Redis单线程。

三、核心使用场景总结

技术核心使用场景典型案例
MULTI/EXEC1. 简单批量执行无依赖的Redis命令;
2. 无需条件判断、仅需“批量提交”的场景;
3. 能容忍“部分命令失败”的场景
批量设置缓存、批量更新无依赖的计数key
Lua 脚本1. 需要原子执行含条件判断/依赖逻辑的操作;
2. 需降低网络往返开销的高频操作;
3. 自定义Redis原子操作(原生命令无法满足)
库存扣减(防超卖)、分布式锁释放、限流算法、红包拆分

四、生产环境最佳实践

  1. MULTI/EXEC

    • 避免在事务中执行过多命令(占用连接时间长);
    • 配合WATCH实现乐观锁,但仅适用于低并发场景;
    • 不依赖“事务回滚”,提前校验命令合法性(避免运行时错误)。
  2. Lua 脚本

    • 脚本长度控制在1KB内,避免大脚本阻塞Redis;
    • 脚本内避免循环(尤其是无限循环),防止Redis卡死;
    • 优先使用redis.call(失败抛出异常)而非redis.pcall(失败返回错误),便于捕获问题;
    • 通过SCRIPT LOAD+EVALSHA复用脚本,减少网络传输。
  3. 资源管理通用规则

    • 所有Redis操作必须添加异常处理,确保连接/资源正常关闭;
    • Spring Boot中优先使用RedisTemplate(自动管理连接池),而非裸用Jedis/Lettuce;
    • 连接池配置合理的最大连接数、空闲超时,避免连接泄露。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1170257.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

办公党狂喜!惠普 Deskjet F4180 一体机驱动稳定版,打印扫描复印全在线

作为小型工作室的打工人&#xff0c;惠普 Deskjet F4180 一体机是我们的核心设备 —— 打印合同、扫描文件、复印资料全靠它&#xff0c;可之前的驱动总是掉链子&#xff1a;扫描时分辨率模糊&#xff0c;复印超过 10 页就卡纸&#xff0c;偶尔还会出现 “驱动冲突” 导致设备离…

2026年嘉应学院寒假算法冬令营结训赛

2026年嘉应学院寒假算法冬令营结训赛A B2029 大象喝水 - 洛谷 数学题,对于圆周率 π ,可以100之后再除回去,避免小数带来的精度误差。 void solve(){int h,r;cin>>h>>r;int sum=h*314*r*r;//cout<&l…

STM32上进行卡尔曼滤波

1.卡尔曼滤波介绍 卡尔曼滤波的核心是融合测量值和系统模型预测值,消除随机噪声,即用动态加权平均,逐步逼近真实状态。 2.程序简单分析 程序上首先初始化滤波器的参数,然后取芯片内部温度传感器的值,然后进行滤波…

上海团队与华盛顿大学联手:AI实现医学图像精准识别突破

这项由上海医疗图像洞察&#xff08;Medical Image Insights&#xff09;团队的史鹏程、陈佳伟、刘佳琦、张星林&#xff0c;联合华盛顿大学的李雷、滑铁卢大学的陈涛以及西安交通大学的研究人员共同完成的重大研究&#xff0c;于2025年11月发表在arXiv预印本服务器上&#xff…

SEO救星上线!Google Search Console新功能手把手教你秒提收录

SEO救星上线&#xff01;Google Search Console新功能手把手教你秒提收录SEO救星上线&#xff01;Google Search Console新功能手把手教你秒提收录先别急着点按钮&#xff0c;把“门”打开再说点“请求索引”之前&#xff0c;先给页面做个“全身体检”1. 看看有没有瞎写 noinde…

微信立减金回收,2026年最聪明的省钱新姿势你真的知道吗 - 京顺回收

春节脚步渐近,不少人翻看微信钱包时,会意外发现里面悄悄积攒了不少“微信立减金”。这些立减金看似金额不大,但日积月累下来,数量也颇为可观。然而,烦恼也随之而来:有些立减金临近过期,只能眼睁睁看着它们失效,…

多模一体破局:金仓数据库引领文档数据库国产化新征程

多模一体破局&#xff1a;金仓数据库引领文档数据库国产化新征程 在数字化转型的深水区&#xff0c;企业对数据处理的期待早已超越简单的存储与调用。文档数据库凭借其对半结构化数据的天然亲和力&#xff0c;已成为现代应用开发的重要支柱。然而&#xff0c;当企业面临技术自主…

跨平台虚拟机网络故障排查

引言跨平台虚拟机网络架构的常见应用场景网络故障对业务连续性的影响排查工具与方法概述常见网络故障类型虚拟机与宿主机通信失败跨虚拟机间通信问题外部网络访问异常DHCP/DNS配置错误防火墙或安全策略阻断基础排查步骤检查虚拟机网络适配器配置&#xff08;NAT/桥接/仅主机模式…

金仓数据库如何以“多模融合”重塑文档数据库新范式:技术实战与代码示例

文章目录金仓数据库如何以“多模融合”重塑文档数据库新范式&#xff1a;技术实战与代码示例一、性能实测&#xff1a;直面行业标杆&#xff0c;展现硬核实力二、内核筑基&#xff1a;企业级能力的原生继承三、无缝迁移与极致可用四、实践验证&#xff1a;电子证照系统的平滑替…

新加坡科技设计大学:AI音乐生成终于学会“听懂“人类喜好了

这项由新加坡科技设计大学AMAAI实验室的Dorien Herremans和Abhinaba Roy共同完成的研究发表于2025年11月&#xff0c;论文编号为arXiv:2511.15038v1。对这项突破性研究感兴趣的读者可以通过该编号查找完整论文内容。说起AI作曲&#xff0c;你可能已经听过那些能根据文字描述生成…

Meta团队首次发现:AI研究助手的成功竟然靠“不断试错“?

一支来自Meta FAIR实验室的研究团队&#xff0c;联合伦敦大学学院、Meta超级智能实验室和英属哥伦比亚大学的学者们&#xff0c;在2025年11月发表了一项开创性研究。这项研究深入探讨了什么让AI研究助手变得更加出色&#xff0c;论文发表在国际顶级学术期刊上&#xff0c;编号为…

《企业元宇宙架构设计,AI应用架构师如何打造经典》

企业元宇宙架构设计&#xff1a;AI应用架构师如何打造经典 一、引言&#xff1a;企业元宇宙不是噱头&#xff0c;是数字化转型的下一站 钩子&#xff1a;你见过“能预测未来”的工厂吗&#xff1f; 去年&#xff0c;我去参观一家长三角的汽车零部件工厂&#xff0c;车间里没有传…

基于 Flutter × OpenHarmony 构建应用选择主题部分实现

文章目录基于 Flutter OpenHarmony 构建应用选择主题部分实现前言背景Flutter OpenHarmony 跨端开发介绍开发核心代码心得总结基于 Flutter OpenHarmony 构建应用选择主题部分实现 前言 在现代移动应用开发中&#xff0c;“关于应用”页面是用户了解应用信息的重要入口。它…

激发集体好奇心的团队活动设计

激发集体好奇心的团队活动设计关键词&#xff1a;集体好奇心、团队活动设计、团队协作、创新思维、互动体验摘要&#xff1a;本文聚焦于激发集体好奇心的团队活动设计。通过系统分析背景&#xff0c;阐述核心概念&#xff0c;介绍具体算法原理与操作步骤&#xff0c;构建数学模…

实用指南:React Native学习路径与资源推荐

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Doris数据导入方案大全:从Kafka到HDFS的完整链路实现

Doris数据导入方案大全:从Kafka到HDFS的完整链路实现 1. 引入与连接 1.1 引人入胜的开场 想象一下,你是一家电商公司的数据分析师,每天都会有海量的用户行为数据产生,比如用户的浏览记录、购买记录、加购行为等等。这些数据就像一座巨大的金矿,如果能合理地挖掘和分析,…

导师推荐8个AI论文工具,专科生轻松搞定毕业论文!

导师推荐8个AI论文工具&#xff0c;专科生轻松搞定毕业论文&#xff01; AI 工具如何助力论文写作&#xff1f; 在当今学术环境中&#xff0c;越来越多的专科生开始借助 AI 工具来提升论文写作效率。尤其是随着 AIGC&#xff08;人工智能生成内容&#xff09;技术的发展&#x…

数据持久化——PlayerPrefs

内存和硬盘内存&#xff08;RAM&#xff09; 是电脑的 “临时工作台”&#xff1a;用于临时存放 CPU 正在处理的数据和程序。CPU 可直接、快速访问内存中的数据&#xff0c;速度以纳秒&#xff08;ns&#xff09;计。断电后数据全部丢失&#xff08;易失性存储&#xff09;。硬…

100个实用小工具8-deepCFD二维流场神经网络 - 详解

100个实用小工具8-deepCFD二维流场神经网络 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas"…

2026国内最新针织高弹面料品牌top10推荐!广东广州等地优质面料供应商权威榜单发布,品质与创新双优助力服饰产业升级 - 品牌推荐2026

随着消费升级与服饰产业智能化转型,针织高弹面料作为服装功能性与舒适性的核心载体,市场需求呈现爆发式增长。据中国纺织工业联合会最新行业报告显示,2025年国内针织高弹面料市场规模突破800亿元,年增长率达15%,但…