redis的事务能保证ACID属性吗

3552 篇文章 108 订阅

前言

说到事务,我们想到的都是关系型数据库能实现的。在Redis中,其实也有实现事务的方法。但为什么我们都说Redis不支持事务呢?那就要说到我们对事务的要求-ACID了。

事务ACID的要求

我们都知道,事务包括原子性、一致性、隔离性、持久性。 简单解释一下4个属性的含义:

  • 原子性: 一个事务中的多个操作必须都完成,或者都不完成。
  • 一致性:数据在事务执行前后,数据库的完整性没有被破坏。 比如销售前库存+售出的个数是100,销售后加起来的个数也是100.
  • 隔离性:在执行一个事务时,任何其他操作无法存取到正在执行事务访问的数据。
  • 持久性:执行事务后,数据的修改要被持久化保存下来。当数据库重启后,数据的值需要是被修改后的值。

Redis的事务

Redis可通过MULTIEXEC来实现事务。使用步骤很简单:

  1. MULTI来声明开启一个事务;
  2. 事务开启后,客户端将要执行的多个操作都发到服务端。但redis不会立刻执行,而是放在一个待执行的队列中。
  3. EXEC命令来执行上述的命令。EXEC执行后,队列中的命令才会在Redis中执行。

来个简单例子:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECR A:num
QUEUED
127.0.0.1:6379> DECR A:num
QUEUED
127.0.0.1:6379> EXEC
1) (integer) -1
2) (integer) -1
复制代码

从例子中能清晰看到EXEC执行后,两个命令才执行。

Redis的事务能满足ACID的哪些属性要求

原子性

首先来看原子性。MULTI和EXEC配合使用,确实可以保证多个操作都完成。但是我们要考虑到事务执行如果出错的情况。 分情况讨论:

  • 执行EXEC命令前的错误:客户端发来的命令本身就有错误,比如说语法错误。该情况在EXEC提交后,Redis会拒绝所有的操作。这种情况能保证原子性。
  • 命令入队列的时候,命令和操作的数据类型不符:这种情况Redis因为还没执行命令,检查不到错误。当执行EXEC后才会报错。这种情况不会拒绝其他的操作,不能保证原子性。
  • 执行EXEC命令时,Redis实例故障:这种情况也会导致事务失败。如果开启了AOF日志,当AOF恢复Redis实例后,事务不会被执行,能保证原子性;但若没有开启AOF,Redis重启后数据丢失,也就不能保证原子性。

一致性

再来看一致性。也要分情况来讨论:

  • 命令入队列的时候报错: 事务本身都不会执行,可以保证一致性。
  • 命令入队列未报错,实际执行时报错:错误的命令不会执行,但正确的会执行,也不会影响一致性。
  • EXEC命令执行时实例故障
      1. 如果没有开启RDB或AOF:数据都丢失了,没有一致性问题。
      1. 开启了RDB快照:因为 RDB 快照不会在事务执行时执行,所以,事务命令操作的结果不会被保存到 RDB 快照中,使用 RDB 快照进行恢复时,数据库里的数据也是一致的。
      1. 开启了AOF日志:如果事务操作还没记录到AOF日志,实例就故障了,那么AOF日志恢复的数据是一致的;如果部分操作被记录到AOF日志,我们可以用redis-check-aof来清除事务中已经完成的操作,数据恢复后也是一致的

隔离性

事务的隔离性保证,要考虑到同时进行的事务操作。

  • 其他事务操作在EXEC命令前执行,此时隔离性的保证要使用WATCH机制来实现,否则隔离性无法保证;
  • 其他事务操作在EXEC命令后执行,此时隔离性可以保证。因为Redis是单线程执行命令,EXEC命令执行后,Redis会保证先把命令队列的所有命令执行完。因此其他事务操作不会破坏事务的隔离性。

WATCH机制

一个事务的EXEC命令还没执行,此时命令还在队列中。此时如果有其他的并发操作,需要看事务是否使用了WATCH机制。若用了WATCH机制,隔离性可保证;否则无法保证事务的隔离性。

WATCH 机制的作用是,在事务执行前,监控一个或多个键的值变化情况,当事务调用 EXEC 命令执行时,WATCH 机制会先检查监控的键是否被其它客户端修改了。如果修改了,就放弃事务执行,避免事务的隔离性被破坏。然后,客户端可以再次执行事务,此时,如果没有并发修改事务数据的操作了,事务就能正常执行,隔离性也得到了保证。

下面是一个watch机制的图例,方便理解它的功能。

持久性

最后说说持久性,持久性取决于Redis的持久化配置模式。

如果说都没开启RDB或者AOF,数据都丢了,事务的持久性肯定得不到保证。

如果你开启了RDB,一个事务执行后,RDB快照还未执行前,此时Redis发生宕机,事务修改的数据丢失了,也不能保证持久化;

如果你开启了AOF,因为 AOF 模式的三种配置选项 no、everysec 和 always 都会存在数据丢失的情况,也不能保证持久化。

小结

从本文对Redis事务的分析,我们能知道为什么说Redis不支持事务,是因为它不能保证ACID属性。 如果业务操作需要事务要求,那么可以使用关系型数据库来实现。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值