一、介绍

Redis的事务并不像Mysql那么灵活,有隔离级别,出问题后还能回滚数据等高级操作。Redis毕竟是非关系型数据库,他目前事务回滚机制是不执行命令,也就是可以采取watch命令模拟乐观锁,进行监听数据,发现数据不是事务开始时候的样子了,那么我这个事务里的命令就不会得到执行。

二、三大命令

首先看下事务的全部命令
大白话讲解Redis的事务_数据库
但核心的命令就三个

  • 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、图示

大白话讲解Redis的事务_分布式_02

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、图示

大白话讲解Redis的事务_redis_03

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
五、个人公众号

微信公众号【Java码农社区】
大白话讲解Redis的事务_分布式_04