redis 事务

本文详细阐述了Redis事务的三个关键阶段(multi, exec, discard),解释了其原子性和不支持回滚的特点。通过实例说明了watch和乐观锁的作用,并探讨了为何在特定场景下Redis事务是必要的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

所谓事务是指不可分割的最小工作单位,要么全部执行成功,要么全部不执行

redis 事务从开始到结束需要经过三个阶段:

  • 事务开始:multi 命令开启一个事务
  • 命令入队:watch、multi、discard、exec 会被立即执行、其他命令依次入队并返回客户端 queued
  • 事务执行:exec 命令开始执行事务

exec:执行事务
discard:关闭事务
watch:加分布式锁
multi:开启事务
queued:命令入队成功

一般情况下不建议使用 redis 事务,因为它不支持回滚,举个例子:

multi
incr a
incr b
incr c
exec

此时即使键 a 对应字符串类型,incr a 执行失败,incr b 和 incr c 一样也会执行,也就是说即使执行出错也不会回滚

那么是不是就说 redis 事务不具备原子性呢?答案是否定的,redis 事务实际是能保证原子性的,先看原子性的定义:

原子性:要么全部执行,要么全部不执行

由于不回滚,redis 事务一旦执行肯定全部执行,在以下两种情况会全部不执行:

  1. 命令本身就是错误的,redis 执行事务前会检查事务命令是否正确,如果存在错误命令就不执行
  2. watch 监视的键值对被修改

watch 实际就是 CAS 乐观锁。调用 watch 指令的客户端会关注指定键值对,如果在关注期间有其他客户端修改了这个键值对,那么调用 watch 指令的客户端下一次事务操作执行失败

从这里也就可以看出,redis 事务是要么全部执行,要么全部不执行,满足原子性。和 mysql 事务相比,区别在于 mysql 事务执行错误后会全部回滚,但 redis 只检查指令是否正确,指令执行错误不会回滚,这里不回滚的原因主要集中在以下两点:

  • 指令执行出错实际是因为开发问题,这种问题应该再开发阶段解决而不是线上
  • 由于事务无需回滚,redis 整体事务逻辑简单且快速,保证高效

最后简单聊聊为什么 redis 需要引入事务:之前提到,redis 由于单线程操作,没有多线程并发操作同一块内存,因此天然线程安全。这句话是没错,但如果多个客户端连接同一个 redis,并且业务代码中没有添加同步判断,仍有可能存在异常情况:

举个例子,客户 a、b 分别从客户端 A、客户端 B 购买同一件商品,商品库存保存在 redis 中并且仅剩一件,此时可能产生如下结果:

  1. 客户端 A 判断库存大于 0 返回 true
  2. 客户端 B 判断库存大于 0 返回 true
  3. 客户 a 从客户端 A 下单成功,商品库存变为 0
  4. 客户 b 由于之前判断有商品,同样下单成功,商品库存变为 -1

出现超卖问题,此时就算使用事务,也无法解决问题。一般需要事务配合 watch 指令一起解决

客户端 B 由于 watch 指令发现库存对应 redis 键值对被修改,事务执行失败,不执行下单逻辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值