Redis事务
事务的本质:一组命令的集合。一个事务中的所有的命令都会被序列化,在事务执行的过程中,会按照顺序执行。
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
批量操作在发送 EXEC 命令前被放入队列缓存。
收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行会经历以下三个阶段:
开始事务(multi)。
命令入队(……)。
执行事务(exec)。
注意:
redis中的单挑命令保证原子性,但是redis事务不保证原子性。
redis中没有隔离级别的概念
所有的事务在事务中并没有直接被执行,只有发起执行命令(Exec)的时候才会执行。
下表列出了 redis 事务的相关命令:
序号 | 命令及描述 |
---|---|
1 | DISCARD 取消事务,放弃执行事务块内的所有命令。 |
2 | EXEC 执行所有事务块内的命令。 |
3 | MULTI 标记一个事务块的开始。 |
4 | UNWATCH 取消 WATCH 命令对所有 key 的监视。 |
5 | [WATCH key key …] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 |
正常执行事务:
127.0.0.1:6379> multi #开启事务
OK
#-----------命令入队---------------
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> mset k3 v3 k4 v4
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> mget k3 k4
QUEUED
#————————————————————————————————
127.0.0.1:6379> exec #执行事务
1) OK
2) OK
3) OK
4) "v1"
5) "v2"
6) 1) "v3"
2) "v4"
#可以发现事务中的命令会按照入队的顺序执行(顺序性)
取消事务
127.0.0.1:6379> multi #开启事务
OK
#-----------命令入队---------------
127.0.0.1:6379> set a 1
QUEUED
127.0.0.1:6379> set b 2
QUEUED
127.0.0.1:6379> set c 3
QUEUED
#————————————————————————————————
127.0.0.1:6379> discard #取消事务
OK
127.0.0.1:6379> get a #得到的a值为nil,所以事务没有执行
(nil)
127.0.0.1:6379>
编译时异常(代码有问题,命令写错),整个事务就不会执行
127.0.0.1:6379> multi #开启事务
OK
#-----------命令入队---------------
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> sett k2 v2 #命令写错
(error) ERR unknown command `sett`, with args beginning with: `k2`, `v2`,
127.0.0.1:6379> set k3 v3
QUEUED
#————————————————————————————————
127.0.0.1:6379> exec #执行事务
(error) EXECABORT Transaction discarded because of previous errors.#事务被取消
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379>
运行时异常(代码正确但是命令执行失败),其他命令会正常执行,执行失败的命令会抛出异常
127.0.0.1:6379> set a "a"
OK
127.0.0.1:6379> incr a
(error) ERR value is not an integer or out of range #字符串无法加一,报错
127.0.0.1:6379> multi #开启事务
OK
#-----------命令入队---------------
127.0.0.1:6379> incr a
QUEUED
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
#————————————————————————————————
127.0.0.1:6379> exec #执行事务
1) (error) ERR value is not an integer or out of range #第一条命令报错执行失败,后续命令继续执行
2) OK
3) OK
4) "v1"
127.0.0.1:6379>
watch 监视(实现乐观锁和悲观锁)
watch命令可以被调用多次。对键的监视从watch执行之后开始生效,直到调用exec为止,不管事务是否成功执行,对所有键的监视都会被取消。
当客户端断开连接时,该客户端对键的监视也会被取消。
unwatch命令可以手动取消对所有键的监视。
1.监视money,正常执行
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set outmoney 0
OK
127.0.0.1:6379> watch money #监视money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby outmoney 20
QUEUED
127.0.0.1:6379> exec #事务执行前,money未被其他命令修改
1) (integer) 80
2) (integer) 20
2.监视money,事务提交前money被其他命令修改
客户端1:
127.0.0.1:6379> set money 500 #如果在客户端2事务执行前,执行这条命令
OK
客户端2:
127.0.0.1:6379> mget money outmoney
1) "70"
2) "30"
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby outmoney 10
QUEUED
127.0.0.1:6379> exec #事务执行前,money被其他命令修改,所以事务被打断
(nil)
127.0.0.1:6379>
给个饭钱?
- Post link: http://sovzn.github.io/2021/02/09/Redis%E5%9F%BA%E6%9C%AC%E7%9A%84%E4%BA%8B%E5%8A%A1%E6%93%8D%E4%BD%9C/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub Issues