一、对比 MySQL 中事务的四大特征
1. 原子性
Redis 中事务的原子性是:将多个操作打包在一起执行,要么全部都执行,要么全部都不执行,则全部都执行时,可能会执行不成功,但此时不会回滚;
MySQL 中事务的原子性则为:将多个操作打包在一起执行,要么全部都执行成功,要么全部都不执行,当执行不成功时,则会回滚;
旧版本的 Redis 官网上对事务的描述为:
但是在新版本中,第一句话被删除了:
可以看出对于事务原子性的定义是更倾向于 MySQL 中事务的原子性,即带有回滚的原子性,在这种情况下看来,Redis 中的事务是不具备原子性的;
2. 一致性
Redis 中的事务不具备一致性,由于 Redis 不涉及 "约束",也没有回滚机制,则在事务执行后,可能会出现数据不一致的情况;
3. 持久性
Redis 是内存数据库,数据是在内存中存储的,虽然 Redis 存在持久化机制,但是和事务无关,即 持久性是指 Redis 的持久性,而并非是 Redis 事务的持久性;
4. 隔离性
Redis 事务不涉及隔离性,因为 Redis 是一个单线程模型的服务器程序,所有的请求 / 事务都是串行执行的;
综上所述,Redis 的事务并不具备 MySQL 事务的四大特征,Redis 事务存在的意义主要是为了 "打包",将多个操作打包为一个整体,防止其他操作穿插执行;
二、事务操作
Redis 事务本质上是在服务器上搞了一个 "事务队列";每次客户端在事务中进行一个操作,都会把命令先发给服务器,放到 "事务队列" 中;当收到执行事务命令 exec 的时候,就会把队列中的这些任务都按照顺序依次进行;
1. 开启事务
MULTI:开启一个事务,执行成功返回 OK
开启事务之后,输入的命令不会立即执行,而是进入队列中
既然不会立即执行,那如果输入错误的 redis 命令会怎么样呢?
可以看出即使不会立即执行,Redis 也会对输入的命令检测;
2. 执行事务
EXEC:真正执行事务,并返回事务中每个操作的执行结果,执行完毕之后结束本次事务
输入 EXEC 命令之后,本次事务就执行完毕了,此时输入的操作就是非事务的操作执行的;
3. 放弃当前事务
DISCARD,丢弃当前事务之后,事务中的操作都不会执行
4. 监控某个 key,在事务执行之前是否发生了改变
WATCH
若存在两个客户端,一个客户端(ubuntu)开启了事务之后,先执行了 set key 111,然后另一个客户端(ubuntu2)没有开启事务,执行了 set key 222,然后客户端(ubuntu)执行了事务,此时get key 得到的结果是 111,因为客户端(ubuntu)虽然先输入 set key 命令,但是是后执行事务的,也就是后执行 set key 命令的;如下图所示
watch 就可以监控 key,在客户端(ubuntu)开启事务并 set key 之后,key 是否再次发生改变,如果该 key 发生改变了,再执行事务,则事务会执行失败;