Redis:代码实战之事务

【关于作者】

关于作者,目前在蚂蚁金服搬砖任职,在支付宝营销投放领域工作了多年,目前在专注于内存数据库相关的应用学习,如果你有任何技术交流或大厂内推及面试咨询,都可以从我的个人博客(https://0522-isniceday.top/)联系我

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m5jfxamr-1681039976332)(https://zhangyuxiangplus.oss-cn-hangzhou.aliyuncs.com/boke//%E4%BA%8B%E5%8A%A1_1681039968197.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KXBNsVLH-1681039976333)(C:/Users/98347/Desktop/%E5%AD%A6%E4%B9%A0%E5%8A%A0%E6%B2%B9%E5%95%8A/redis/%E5%AF%BC%E5%87%BA/%E6%80%9D%E7%BB%B4%E5%AF%BC%E5%9B%BE/%E4%BA%8B%E5%8A%A1.png)]

1.Redis如何实现事务

事务:是指对数据的一系列操作,事务在执行时会提供ACID的数据保证

如何实现:通过MULTI和EXEC命令

步骤:

  • 第一步:通过MULTI开启事务
  • 第二步:将事务中需要执行的指令发送给redis,redis并不会立即执行这些指令,而是会将这些指令放到一个队列中
  • 第三步:发送提交事务的指令EXEC,这时redis会执行队列中的指令

接下来我们看下当前redis通过MULTIEXEC实现的事务是否满足ACID的特性

1.1.原子性

概念:一个事务中的操作要么全部完成,要么都不完成,那么redis事务过程中报错是否会保证原子性呢

主要分三种情形:

  • 执行EXEC命令之前,命令语法就发生异常,此时后续命令仍然能够正常入队

    解决:此时redis会记录下当前报错的指令,当客户端发送EXEC命令之后,redis会拒绝执行队列中所有的命令,返回事务失败的结果。这种场景就能够正常保证原子性了

  • 事务操作类型和数据不匹配,该命令能够正常入队,但是EXEC命令执行之后发现报错,并且队列中的其他语句也执行正常

    解决:针对这种异常场景,redis并没有像MySQL一样提供了回滚的策略,因此这个场景下无法保证原子性

    DISCARD命令:主动放弃事务执行,将缓存的命令队列清空

  • 执行事务EXEC命令时,redis实例发生了故障,导致事务执行失败

    解决:如果采取的是AOF日志,那么可能会存在部分命令写入了AOF日志,此时需要使用redis-check-aof工具检查AOF文件,这个工具能够将已完成的事务操作从AOF文件中去除,这样AOF恢复实例后,事务操作不会再被执行,从而保证了原子性。如果没有采取AOF,那么这个失败的事务的数据都无法恢复,自然谈不上原子性。但是RDB却可以保证,由于事务执行时RDB无法执行,因此不会出现事务写一半就宕机,然后数据库恢复后还保存事务写入的那部分数据。

1.2.一致性

一致性:一致性根据不同的事务场景会有概念上的区分,一般来说一致性代表从一个一致性状态变成了另外一个一致性状态,例如MySQL的一致性就是代表数据从数据都满足约束条件(外键、唯一性索引等)到另外一个满足约束条件的状态,所以mysql中的一致性就是数据的约束条件没有被破坏。而redis的一致性的定义可以理解为数据没有被破坏,数据都是按照redis的结构存储,redis可用这样理解。

如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已写入物理数据库,这是数据库就处于一种不正确的状态,也就是不一致的状态

而redis事务的一致性也可以分为三个情况来看:

  • 命令入队时报错

    此时redis不会执行该事务,因此一致性没有被破坏

  • 命令入队时没报错,执行时报错

    错误的执行无法执行,正确的指令得到执行,因此不会改变数据库的一致性

  • EXEC执行时实例发生故障

    没有开启AOF或RDB,实例恢复后,事务的数据丢失,无法恢复,redis的数据自然维持了一致性

    如果开启了RDB,由于RDB快照不会在事务执行的时候执行,所以实例恢复后,事务数据仍然不存在于实例,也保持了一致性

    如果开启了AOF,这里就同原子性了,可以用redis-check-aof工具,也能保持一致性

总结来说,在命令执行角度、实例故障角度,redis事务都不会发生一致性的错误

1.3.隔离性

隔离性:数据库在执行一个事务时,其他事务无法读取到正在执行事务访问的数据

事务的隔离性要求,会受到并发事务的影响,而并发事务分为两种

  • EXEC之前执行的并发操作
  • EXEC之后执行的并发操作

这对这两种情况,只有第一种会产生隔离性的影响,此时redis可以采取watch机制进行解决:

Watch机制:事务执行前,会监控一个或多个键值的变化,在事务执行EXEC命令时,会先检查监控的键值是否有被修改,如果键值被修改了则放弃事务执行,如果没被修改,事务正常执行,保证了事务的隔离性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-63gxNoq4-1681039976335)(C:%5CUsers%5C98347%5CDesktop%5C%E5%AD%A6%E4%B9%A0%E5%8A%A0%E6%B2%B9%E5%95%8A%5Credis%5C%E5%9B%BE%E7%89%87%E8%B5%84%E6%BA%90%5C4f8589410f77df16311dd29131676373.jpg)]

此时也可以采取pipline的方式去解决,将命令通过pipline的形式发送给redis执行(推荐)。因为采取MULTI、EXEC每次都得发送指令给redis,网络开销相较于pipline大,并且pipline中的命令会一起执行,由于redis是单线程,这样就不存在发送MULTI命令,其他并发请求数据的情形了,自然保证了数据的隔离性。

针对第二种情形,EXEC之后执行并发操作,由于redis是单线程处理用户请求,因此不会产生隔离性的问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O8JfrAwk-1681039976335)(C:%5CUsers%5C98347%5CDesktop%5C%E5%AD%A6%E4%B9%A0%E5%8A%A0%E6%B2%B9%E5%95%8A%5Credis%5C%E5%9B%BE%E7%89%87%E8%B5%84%E6%BA%90%5C11a1eff930920a0b423a6e46c23f44ae.jpg)]

1.4.持久性

redis没有采用AOF或RDB数据持久化的话,持久性自然得不到保障

采取RDB,由于事务执行时,RDB无法运行,因此事务执行过程中如果发生了实例的故障,那么数据就会丢失,无法保证持久性

采取AOF,不管采取何种写回策略,都存在数据丢失的风险,因此也无法保证持久性

2.小结

我们通过MULTI、EXEC、DISCARD、WATCH四个指令来支持事务:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w7DZQkSI-1681039976336)(C:%5CUsers%5C98347%5CDesktop%5C%E5%AD%A6%E4%B9%A0%E5%8A%A0%E6%B2%B9%E5%95%8A%5Credis%5C%E5%9B%BE%E7%89%87%E8%B5%84%E6%BA%90%5C9571308df0620214d7ccb2f2cc73a250.jpg)]

事务的ACID特性,是事务保证正确性的基本要求,而Redis能够保证事务的一致性、隔离性,但是无法保证事务的持久性,在事务中命令语法有误时,也无法保证原子性

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈哈哈张大侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值