redis系列之——事物及乐观锁

兄弟打扰一下,redis系列之——事物及乐观锁
最新回答
你我咫尺之隔

2026-01-19 07:39:38

Redis支持事务,但属于弱事务,不具备ACID特性中的隔离性,且多条命令不保证原子性。其事务本质是一组命令的集合,通过MULTI/EXEC/DISCARD命令实现,而乐观锁通过WATCH命令实现。以下是具体说明:

事务(MULTI/EXEC/DISCARD)
  • 核心特性

    弱事务性:Redis事务没有隔离级别,事务中的命令不会立即执行,而是先序列化存入队列,执行时按顺序处理。

    非原子性:单条命令原子性由Redis保证,但事务内多条命令若部分失败,不会回滚已执行的命令。

    执行流程:

    开启事务:MULTI 命令标记事务开始。

    命令入队:后续命令依次加入队列,返回QUEUED状态。

    执行事务:EXEC 命令触发队列中所有命令按顺序执行。

    取消事务:DISCARD 命令清空队列并退出事务模式。

  • 示例场景

    正常执行:

    127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET name wuxlQUEUED127.0.0.1:6379> SET age 30QUEUED127.0.0.1:6379> EXEC1) OK2) OK

    取消事务:

    127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET name wuxlQUEUED127.0.0.1:6379> DISCARDOK127.0.0.1:6379> GET name(nil)
  • 错误处理

    编译错误:命令入队时因语法错误被拒绝,后续EXEC会失败并清空队列。

    127.0.0.1:6379> MULTIOK127.0.0.1:6379> GET # 错误命令(error) ERR wrong number of arguments for 'get' command127.0.0.1:6379> EXEC(error) EXECABORT Transaction discarded because of previous errors.

    运行时错误:命令入队时正确,但执行时因类型不匹配等逻辑错误失败,不影响其他命令。

    127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET name wuxlQUEUED127.0.0.1:6379> INCR name # 对字符串执行自增操作QUEUED127.0.0.1:6379> EXEC1) OK2) (error) ERR value is not an integer or out of range
乐观锁(WATCH)
  • 核心机制

    监控键值:WATCH 命令监视一个或多个键,若事务执行前被其他客户端修改,则事务中断。

    无阻塞设计:相比悲观锁(如MySQL的行锁),乐观锁通过版本检查实现并发控制,避免性能损耗。

  • 应用场景

    转账模拟:

    初始化数据:

    127.0.0.1:6379> SET acc1 1000OK127.0.0.1:6379> SET acc2 0OK

    客户端A监控并开启事务:

    127.0.0.1:6379> WATCH acc1OK127.0.0.1:6379> MULTIOK127.0.0.1:6379> DECRBY acc1 100QUEUED127.0.0.1:6379> INCRBY acc2 100QUEUED

    客户端B修改数据:

    127.0.0.1:6379> INCRBY acc1 1000(integer) 2000

    客户端A执行事务:

    127.0.0.1:6379> EXEC(nil) # 事务因acc1被修改而失败
  • 注意事项

    监控失效条件:WATCH 的键若在EXEC前被修改(无论由哪个客户端触发),事务均会失败。

    重试机制:事务失败后需重新获取数据并重试,适合低冲突场景。

总结
  • 事务适用性:Redis事务适合需要命令序列化执行的场景(如批量更新),但需接受其非原子性和无隔离性的限制。
  • 乐观锁优势:通过WATCH 实现无锁并发控制,适合冲突率低的场景(如分布式计数器),但需应用层处理重试逻辑。
  • 生产建议:高并发或强一致性需求下,可结合Lua脚本(保证原子性)或外部锁机制增强可靠性。