一、事务特性
我们之前接触的事务是数据库的事务,回忆一下数据库事务的特性
ACID四大特性 分别代表
**原子性(Atomicity)**原子性保证事务中的所有操作要么全部成功,要么全部回滚,即事务是不可分割的最小工作单位。
**一致性(Consistency)**一致性保证事务开始前和结束后,数据库的状态必须满足所有定义的约束,如主键、外键、检查约束等。事务执行过程中不会违反这些约束。
**隔离性(Isolation)**隔离性保证多个事务并发执行时,一个事务的操作对其他事务是不可见的,中间状态不会被其他事务看到。
持久性(Durability)持久性保证事务一旦提交,数据修改将永久保存到数据库中,即使系统故障也不会丢失。
Redis的事务和数据库事务特性有着很大差异
原子性:Redis的原子性一直有着很大争议
- 上文说到数据库的事务是保证所有操作全部成功,如果操作有误就回滚
- 而Redis的事务不保证成功,如果操作有误失败就失败了,也不会回滚
查阅官方文档

图1是旧版本Redis关于事务的说明,图2是新版本Redis关于事务的说明,可以很明显看到,Redis官方将第一句删除了,说明一开始官方是认为Redis事务是原子性的,但是因为数据库的事务拉高了原子性的标准并且得到了大多数人的认可,所以官方将事务原子性的说明删除了
所以我们认为Redis事务不具有原子性
不具备一致性:Redis没有约束也没有回滚机制,事务执行过程如果某个修改操作出现失败,就可能引起不一致的情况
不具备持久性:Redis本身就是内存数据库,数据是存储在内存中的
不涉及隔离性:Redis是一个单线程模型的服务器程序,所有请求/事务,都是"串行"执行的
二、事务本质
Redis 事务本质上是在服务器上搞了⼀个 "事务队列". 每次客⼾端在事务中进⾏⼀个操作,都会把命令先发给服务器, 放到 "事务队列" 中,但是并不会⽴即执⾏,⽽是会在真正收到 EXEC 命令之后, 才真正执⾏队列中的所有操作.
因此, Redis 的事务的功能相⽐于 MySQL 来说, 是弱化很多的. 只能保证事务中的这⼏个操作是 "连续的", 不会被别的客⼾端 "加塞", 仅此⽽已
三、操作命令
3.1 MULTI
MULTI | Docs
https://redis.io/docs/latest/commands/multi/开启⼀个事务, 执⾏成功返回OK
3.2 EXEC
EXEC | Docs
https://redis.io/docs/latest/commands/exec/真正执⾏事务


我们multi开启事务,设置key1key2key3,之后,再开启一个客户端,来获取这三个键,结果返回nil,说明第一个客户端的的set命令都没有执行,其实是都存进入事务队列


此时我们执行EXEC命令,返回三个ok,这是执行三个set命令的返回值,我们再get一下,发现Redis里有这个值,说明执行成功
3.3 DISCARD
DISCARD | Docs
https://redis.io/docs/latest/commands/discard/放弃当前事务,此时直接清空事务队列,之前的操作都不会真正执⾏到

开启事务之后我们设置键值对,执行discard命令,就会抛弃当前事务,以上命令set命令都不会执行。再执行get命令,结果返回nil,说明set命令未执行
3.4 WATCH
在执⾏事务的时候, 如果某个事务中修改的值, 被别的客⼾端修改了, 此时就容易出现数据不⼀致的问题
WATCH | Docs
https://redis.io/docs/latest/commands/watch/



在两个客户端中
从输入命令的时间看,客户端1先执行set key1 111,客户端2后执行的set key1 222
但是从执行时间看,客户端1是后执行,客户端2是先执行的
这个时候就容易引起歧义,因此即使我们不保证严格的隔离性,至少也要告诉用户,当前这个操作是有风险的
这个时候就可以使用watch命令,可以用watch监控一组key
- 当开启事务的时候,如果对watch的key进行修改,就会记录当前key的版本号(版本号是一个简单的整数,每次修改都会使版本变大,服务器来维护每个key的版本号)
- 当真正提交事务的时候,如果发现当前服务器上的key的版本号已经超过了事务开始时的版本号,就会让事务执行失败


监控k1,开启事务,set k1 100和set k2 1000,只是放入事务队列,不执行。然后在另一个客户端set k1 200,之后在执行EXEC命令执行事务,此时返回nil,获取k1和k2也确实验证没有执行事务的命令。
这是因为watch监控k1,结果k1被修改了,版本号就会改变,如果版本号不一致,就会自动取消事务,事务中的命令都没有执行

3.5 unwatch
UNWATCH | Docs
https://redis.io/docs/latest/commands/unwatch/取消对key的监控,相当于WATCH的逆操作