Redis 事务

Redis 的事务和 MySQL 的事务概念上是类似的,都是把⼀系列操作绑定成⼀组,让这⼀组能够批量执行。但是注意体会 Redis 的事务和 MySQL 事务的区别:

  • 弱化的原子性:Redis 没有 “回滚机制”,只能做到这些操作 “批量执行”,不能做到 “⼀个失败就恢复到初始状态”。
  • 不保证一致性:不涉及 “约束”,也没有回滚。MySQL 的⼀致性体现的是运行事务前和运行后 , 结果都是合理有效的,不会出现中间非法状态。
  • 不需要隔离性:也没有隔离级别,因为不会并发执行事务 (redis 单线程处理请求) 。
  • 不需要持久性:是保存在内存的,是否开启持久化, 是 redis-server 自己的事情, 和事务无关。

Redis 事务本质上是在服务器上搞了⼀个 “事务队列”,每次客户端在事务中进行一个操作,都会把命令先发给服务器,放到 “事务队列” 中(但是并不会立即执行) 而是会在真正收到 EXEC 命令之后,才真正执行队列中的所有操作。 因此,Redis 的事务的功能相比于 MySQL 来说,是弱化很多的;只能保证事务中的操作是 “连续 的”,不会被别的客户端 “加塞”,仅此而已。

事务操作

MULTI

开启⼀个事务,执行成功返回 OK。

示例

127.0.0.1:6379> MULTI
OK

EXEC

真正执行事务。

示例

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> set k2 2
QUEUED
127.0.0.1:6379> set k3 3
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) OK

每次添加⼀个操作,都会提示 “QUEUED”,说明命令已经进入客户端的队列了。

真正执行 EXEC 的时候,客户端才会真正把上述操作发送给服务器。此时就可以获取到上述 key 的值了。

127.0.0.1:6379> get k1
"1"
127.0.0.1:6379> get k2
"2"
127.0.0.1:6379> get k3
"3"

DISCARD

放弃当前事务。此时直接清空事务队列,之前的操作都不会真正执行到。

示例

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> set k2 2
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k2
(nil)

WATCH

在执行事务的时候,如果某个事务中修改的值,被别的客户端修改了,此时就容易出现数据不⼀致的问题。

示例

# 客户端1 先执⾏
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set key 100
QUEUED

# 客户端2 再执⾏
127.0.0.1:6379> set key 200
OK

# 客户端1 最后执⾏
127.0.0.1:6379> EXEC
1) OK

此时,key 的值是多少呢?

从输入的命令的时间看,是客户端1先执行的 set key 100;客户端2后执行的 set key 200。但是从实际的执行时间看,是客户端2先执行的,客户端1后执行的。

127.0.0.1:6379> get key 
"100"

这个时候,其实就容易引起歧义。因此,即使不保证严格的隔离性,至少也要告诉用户,当前的操作可能存在风险

watch 命令就是用来解决这个问题的。watch 在该客户端上监控⼀组具体的 key。

  • 当开启事务的时候,如果对 watch 的 key 进行修改,就会记录当前 key 的"版本号"(版本号是个简单的整数,每次修改都会使版本变大。服务器来维护每个 key 的版本号情况)
  • 在真正提交事务的时候,如果发现当前服务器上的 key 的版本号已经超过了事务开始时的版本号,就会让事务执行失败。(事务中的所有操作都不执行)。

示例

客户端1先执行

127.0.0.1:6379> watch k1 # 开始监控 k1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 100 # 进⾏修改, 从服务器获取 k1 的版本号是 0. 记录 k1 的版本号
QUEUED
127.0.0.1:6379> set k2 1000 
QUEUED

只是入队列,但是不提交事务执行。

客户端2再执行

127.0.0.1:6379> set k1 200 # 修改成功, 使服务器端的 k1 的版本号 0 -> 1
OK

客户端1再执行

127.0.0.1:6379> EXEC # 真正执⾏修改操作, 此时对⽐版本发现, 客户端的 k1 的版本被修改,事务不执行
(nil)
127.0.0.1:6379> get k1
"200"
127.0.0.1:6379> get k2
(nil)

此时说明事务已经被取消了,这次提交的所有命令都没有执行

UNWATCH

取消对 key 的监控,相当于 WATCH 的逆操作

你可能感兴趣的:(Redis,redis)