一、介绍
Redis的事务并不像Mysql那么灵活,有隔离级别,出问题后还能回滚数据等高级操作。Redis毕竟是非关系型数据库,他目前事务回滚机制是不执行命令,也就是可以采取watch命令模拟乐观锁,进行监听数据,发现数据不是事务开始时候的样子了,那么我这个事务里的命令就不会得到执行。
二、三大命令
首先看下事务的全部命令
但核心的命令就三个
- MULTI:开始事务。
- EXEC:执行事务,也就是说只有EXEC命令执行的时候,这个事务内的语句才会真正的得到执行。
- WATCH:监听数据变化,在开始事务之前执行。
三、实战
1、MULTI/EXEC
1.1、描述
谁的exec先到达先处理谁的事务,比如有2个客户端,第一个发送mutil开启事务,然后执行了get k1操作,第二个客户端同样发送mutil开启事务,然后执行了del k1操作。由于redis是单进程单线程的,所以这两个client发送的命令执行肯定有先后顺序,那么哪个先执行呢?完全取决于exec命令,看exec命令哪个先到达先处理哪个。比如1的exec先到达,那就先get,然后client2的exec到了则在处理del。
1.2、图示
1.3、代码
# 先设置k1为2
set k1 2
# 客户端1
127.0.0.1:6380> MULTI
OK
127.0.0.1:6380> get k1
QUEUED
# 客户端2
127.0.0.1:6380> MULTI
OK
127.0.0.1:6380> del k1
QUEUED
# 然后客户端2执行exec
127.0.0.1:6380> EXEC
1) (integer) 1
# 然后客户端1执行exec,结果发现nil了,被删了。 类似于mysql中的读已提交。不是RR。
127.0.0.1:6380> EXEC
1) (nil)
2、WATCH/MULTI/EXEC
2.1、描述
乐观锁的功能,比如先发送watch进行监听到当前k1的值是3,然后开启事务,执行 get k1,这时候 exec还没执行,所以整个事务不会执行。在这期间client2执行了set k1 4(下图是del语句,一样的盗里),且exec先到达执行完毕了。这时候client1再执行exec的时候发现k1的值已经变化了,则redis会为我们回滚这条语句,不进行执行client1的事务。
2.2、图示
2.3、代码
set k1 2
# 客户端1
127.0.0.1:6380> watch k1
OK
127.0.0.1:6380> MULTI
OK
127.0.0.1:6380> set k1 5
QUEUED
127.0.0.1:6380> get k1
QUEUED
# 客户端2
127.0.0.1:6380> MULTI
OK
127.0.0.1:6380> set k1 adasdad
QUEUED
# 提交客户端2的事务
127.0.0.1:6380> exec
1) OK
# 提交客户端1的事务,发现报错了。redis里面不会有异常,只会有语法错误,nil在这里就可以理解这个事务没执行,因为他监测到k1数据变化了
127.0.0.1:6380> exec
(nil)
3、说明
- 开启事务后每次执行命令都返回一个QUEUE,代表开启事务后每个命令都在queue里,并没有得到执行,exec后才执行
- watch监听到数据有变化,则命令不会执行。返回了nil,疑问:为什么nil不是事务里命令的正常返回值呢?
我们事务里两个命令,他只返回了一个nil,有头皮屑想也是命令没得到执行。否则就返回两条结果了。
四、总结
- 介绍&&与mysql事务区别
- WATCH/MULTI/EXEC的作用
- 实战
- 事务开启后,每次执行命令都是放到QUEUE