news 2026/5/30 14:13:25

如何在C++中使用Redis的事务功能?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何在C++中使用Redis的事务功能?

一、Redis 事务核心原理(C++ 视角)

Redis 事务通过MULTI(开启事务)→ 执行多个命令(入队)→EXEC(提交事务)/DISCARD(取消事务)完成,hiredis 库中需按此流程依次发送命令,且所有入队命令仅在 EXEC 后执行

  • WATCH:可选,监控指定 key,若事务执行前 key 被修改,事务会被取消(乐观锁);
  • MULTI:标记事务开始,后续命令进入队列而非立即执行;
  • EXEC:执行队列中的所有命令,返回所有命令结果;
  • DISCARD:清空队列,取消事务。

二、C++ 实现 Redis 事务的完整代码

以下示例包含基础事务、带 WATCH 的事务、取消事务三种场景,基于 hiredis 库实现:

cpp

运行

#include <iostream> #include <string> #include <hiredis/hiredis.h> using namespace std; // 连接Redis(复用之前的连接函数) redisContext* connectRedis(const string& ip, int port, const string& password = "") { struct timeval timeout = {10, 0}; redisContext* ctx = redisConnectWithTimeout(ip.c_str(), port, timeout); if (ctx == nullptr || ctx->err) { if (ctx) { cerr << "连接失败:" << ctx->errstr << endl; redisFree(ctx); } else { cerr << "连接对象创建失败!" << endl; } return nullptr; } // 密码认证 if (!password.empty()) { redisReply* reply = (redisReply*)redisCommand(ctx, "AUTH %s", password.c_str()); if (reply == nullptr || reply->type == REDIS_REPLY_ERROR) { cerr << "认证失败:" << (reply ? reply->str : "无返回") << endl; freeReplyObject(reply); redisFree(ctx); return nullptr; } freeReplyObject(reply); } return ctx; } // 执行单个Redis命令(辅助函数) redisReply* execCmd(redisContext* ctx, const char* cmd, ...) { if (!ctx) return nullptr; va_list args; va_start(args, cmd); redisReply* reply = (redisReply*)redisvCommand(ctx, cmd, args); va_end(args); if (reply && reply->type == REDIS_REPLY_ERROR) { cerr << "命令错误:" << reply->str << endl; } return reply; } int main() { // 1. 连接Redis(替换为你的配置) redisContext* ctx = connectRedis("127.0.0.1", 6379, ""); if (!ctx) return -1; // ==================== 场景1:基础事务(MULTI + EXEC) ==================== cout << "===== 基础事务 =====" << endl; // 1.1 开启事务 redisReply* reply = execCmd(ctx, "MULTI"); if (reply && reply->str == string("OK")) { cout << "事务已开启" << endl; } freeReplyObject(reply); // 1.2 入队命令(仅入队,不执行) reply = execCmd(ctx, "SET user:1:name Alice"); // 命令1 freeReplyObject(reply); reply = execCmd(ctx, "HSET user:1 age 25 gender female"); // 命令2 freeReplyObject(reply); reply = execCmd(ctx, "GET user:1:name"); // 命令3 freeReplyObject(reply); // 1.3 提交事务(执行所有入队命令) reply = execCmd(ctx, "EXEC"); if (reply && reply->type == REDIS_REPLY_ARRAY) { cout << "事务执行结果:" << endl; // 遍历EXEC返回的数组(对应入队命令的结果) for (size_t i = 0; i < reply->elements; i++) { redisReply* elem = reply->element[i]; if (elem->type == REDIS_REPLY_STATUS) { cout << " 命令" << i+1 << ":" << elem->str << endl; } else if (elem->type == REDIS_REPLY_STRING) { cout << " 命令" << i+1 << ":" << elem->str << endl; } else if (elem->type == REDIS_REPLY_INTEGER) { cout << " 命令" << i+1 << ":" << elem->integer << endl; } } } freeReplyObject(reply); // ==================== 场景2:带WATCH的事务(乐观锁) ==================== cout << "\n===== 带WATCH的事务 =====" << endl; // 2.1 先设置一个初始值 reply = execCmd(ctx, "SET balance 100"); freeReplyObject(reply); // 2.2 监控balance键(乐观锁:若该键被修改,事务取消) reply = execCmd(ctx, "WATCH balance"); freeReplyObject(reply); // 2.3 开启事务,入队扣减余额命令 reply = execCmd(ctx, "MULTI"); freeReplyObject(reply); reply = execCmd(ctx, "DECRBY balance 50"); // 扣减50 freeReplyObject(reply); // 【模拟其他客户端修改balance(触发WATCH)】 // 注释掉这行,事务会成功;放开注释,事务会返回空(执行失败) // reply = execCmd(ctx, "SET balance 200"); // 外部修改WATCH的key // freeReplyObject(reply); // 2.4 提交事务 reply = execCmd(ctx, "EXEC"); if (reply == nullptr) { cout << "事务执行失败(连接异常)" << endl; } else if (reply->type == REDIS_REPLY_NIL) { // WATCH的key被修改,事务取消,EXEC返回nil cout << "事务取消(WATCH的key被修改)" << endl; } else if (reply->type == REDIS_REPLY_ARRAY) { cout << "事务成功,扣减后余额:" << reply->element[0]->integer << endl; } freeReplyObject(reply); // ==================== 场景3:取消事务(DISCARD) ==================== cout << "\n===== 取消事务 =====" << endl; reply = execCmd(ctx, "MULTI"); freeReplyObject(reply); reply = execCmd(ctx, "SET temp key123"); // 入队一个命令 freeReplyObject(reply); // 取消事务(清空队列) reply = execCmd(ctx, "DISCARD"); if (reply && reply->str == string("OK")) { cout << "事务已取消" << endl; } freeReplyObject(reply); // 验证temp键是否存在(应为不存在) reply = execCmd(ctx, "GET temp"); if (reply->type == REDIS_REPLY_NIL) { cout << "temp键未被设置(事务取消生效)" << endl; } freeReplyObject(reply); // 断开连接 redisFree(ctx); return 0; }

三、核心代码解释

  1. 事务流程关键步骤

    • WATCH balance:监控balance键,若事务执行前该键被其他客户端修改,EXEC会返回nil,事务取消;
    • MULTI:开启事务后,后续SET/HSET/DECRBY等命令仅入队,不会立即执行;
    • EXEC:提交事务,Redis 批量执行队列中的所有命令,返回一个数组(每个元素对应入队命令的结果);
    • DISCARD:清空命令队列,取消当前事务,不会执行任何入队命令。
  2. EXEC 返回值处理

    • 事务成功:返回REDIS_REPLY_ARRAY类型,数组长度等于入队命令数,每个元素对应命令的执行结果;
    • 事务取消(WATCH 触发):返回REDIS_REPLY_NIL
    • 命令错误:入队时语法错误会直接返回错误,但不影响其他命令入队;运行时错误(如对字符串执行 HSET)仅该命令失败,其他命令仍执行(Redis 事务不支持回滚)。

四、Redis 事务的注意事项(C++ 开发重点)

  1. 无回滚机制:Redis 事务中某条命令执行失败(如类型错误),其他命令仍会执行,需在代码中自行校验命令合法性;
  2. WATCH 仅一次有效EXEC/DISCARD后,WATCH会自动取消,若需再次监控需重新执行WATCH
  3. 资源释放:每个redisReply都需调用freeReplyObject释放,避免内存泄漏;
  4. 连接异常处理:事务执行中若连接断开,队列中的命令不会执行,需在代码中增加重连和重试逻辑;
  5. 进阶替代方案:若需强事务支持(如回滚),可使用 Redis 6.0 + 的CLUSTER事务或 Lua 脚本(EVAL),Lua 脚本会原子性执行所有命令,且支持条件判断。

总结

  1. C++ 中使用 Redis 事务的核心流程是:WATCH(可选) → MULTI → 入队命令 → EXEC/DISCARD
  2. EXEC的返回值是数组类型,需遍历解析每个命令的结果,WATCH触发时返回nil
  3. Redis 事务无回滚机制,需注意命令合法性校验,且WATCH仅提供乐观锁能力。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 11:16:01

【好写作AI】别慌!“AI痕迹”检测,到底在检测什么?

好写作AI官方网址&#xff1a;https://www.haoxiezuo.cn/一、新的焦虑正在蔓延&#xff1a;你的论文&#xff0c;有“AI味”吗&#xff1f; 提交论文前&#xff0c;除了查重&#xff0c;你是不是开始多了一个动作——把文段丢进各种“AI检测器”&#xff0c;紧张地等待结果&…

作者头像 李华
网站建设 2026/5/26 17:44:44

制造工厂研发人员需要实现5个SolidWorks共享一台服务器如何实现

在制造工厂中&#xff0c;当5名SolidWorks研发人员需要共享一台服务器时&#xff0c;合理的配置和优化能够显著提升协作效率和数据安全性。此方案核心在于集中化资源管理、动态化资源分配、智能化权限管控&#xff0c;结合高性能硬件配置与协同设计功能&#xff0c;可显著提升资…

作者头像 李华
网站建设 2026/5/29 13:43:57

数据不会说话?虎贲等考 AI 数据分析:让论文实证硬核到惊艳导师

还在对着一堆问卷数据、实验结果抓耳挠腮&#xff1f;用 SPSS 半天跑不出一个相关性分析&#xff0c;用 Excel 画的图表被批 “小学生水平”&#xff1f;辛苦收集的数据&#xff0c;最后只能用干巴巴的文字描述&#xff0c;论文实证部分毫无说服力&#xff1f; 在论文写作的实…

作者头像 李华
网站建设 2026/5/30 0:20:45

打破“数据孤岛”,实现全厂设备一站式可视化管理

核心痛点&#xff1a;在传统的制造工厂中&#xff0c;不同品牌、不同型号的PLC&#xff08;西门子、三菱、欧姆龙等&#xff09;控制着生产线上的各类设备。这些设备数据相互隔绝&#xff0c;形成一个个“数据孤岛”。管理者无法实时掌握设备运行状态、工艺参数、故障信息&…

作者头像 李华
网站建设 2026/5/29 17:51:46

Python+Vue的线上社区信息发布管理平台设计 Pycharm django flask

收藏关注不迷路&#xff01;&#xff01;需要的小伙伴可以发链接或者截图给我 项目介绍 随着互联网技术的不断发展&#xff0c;线上社区已经成为了人们日常生活中不可或缺的一部分。在这样的背景下&#xff0c;为了更好地服务社区用户&#xff0c;提高信息传递的效率和准确性&a…

作者头像 李华