
1.Redis如何实现事务
事务:是指对数据的一系列操作,事务在执行时会提供ACID的数据保证
如何实现:通过MULTI和EXEC命令
步骤:
- 第一步:通过
MULTI
开启事务
- 第二步:将事务中需要执行的指令发送给redis,redis并不会立即执行这些指令,而是会将这些指令放到一个队列中
- 第三步:发送提交事务的指令
EXEC
,这时redis会执行队列中的指令
接下来我们看下当前redis通过MULTI
和EXEC
实现的事务是否满足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
命令时,会先检查监控的键值是否有被修改,如果键值被修改了则放弃事务执行,如果没被修改,事务正常执行,保证了事务的隔离性

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

1.4.持久性
redis没有采用AOF或RDB数据持久化的话,持久性自然得不到保障
采取RDB,由于事务执行时,RDB无法运行,因此事务执行过程中如果发生了实例的故障,那么数据就会丢失,无法保证持久性
采取AOF,不管采取何种写回策略,都存在数据丢失的风险,因此也无法保证持久性
2.小结
我们通过MULTI、EXEC、DISCARD、WATCH
四个指令来支持事务:

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