一、Redis事务

redis事务是可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。参考网址:https://redis.io/docs/manual/transactions/

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务:以MULTI开始一个事务。
  • 命令入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面。
  • 执行事务:由EXEC命令触发事务。

二、Redis事务特性

Redis 事务具有两个重要特性:

1) 单独的隔离操作

事务中的所有命令都会被序列化,它们将按照顺序执行,并且在执行过的程中,不会被其他客户端发送来的命令打断。

2) 不保证原子性

在 Redis 的事务中,如果存在命令执行失败的情况,那么其他命令依然会被执行,不支持事务回滚机制。
注意:Redis 不支持事务回滚,原因在于 Redis 是一款基于内存的存储系统,其内部结构比较简单,若支持回滚机制,则让其变得冗余,并且损耗性能,这与 Redis 简单、快速的理念不相符合。

三、Redis事务命令

Redis事务命令

命令

说明

MULTI

开启一个事务

EXEC

执行事务中的所有命令

WATCH key [key ...]

在开启事务之前用来监视一个或多个key 。如果事务执行时这些 key 被改动过,那么事务将被打断。

DISCARD

取消事务。

UNWATCH

取消 WATCH 命令对 key 的监控。

四、Redis事务案例演示

案例一:事务的正常执行

由MULTI开始事务,由EXEC执行事务,案例如下:

Warning: Using a password with '-a' or '-u' option on the command line in                                                            terface may not be safe.
127.0.0.1:6379>
# 开启一个事务
127.0.0.1:6379> MULTI
OK
# 执行下面三个命令,让其入队到同一个事务中
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> INCR count
QUEUED
# 执行事务
127.0.0.1:6379(TX)> EXEC
1) OK
2) OK
3) (integer) 1
127.0.0.1:6379>

案例二:放弃事务

使用命令MULTI开启事务,DISCARD放弃事务

# 开启事务
127.0.0.1:6379> MULTI
OK
# 将两个命令入队到事务中
127.0.0.1:6379(TX)> set k1 100
QUEUED
127.0.0.1:6379(TX)> set k2 200
QUEUED
# 放弃从事务
127.0.0.1:6379(TX)> DISCARD
OK
# 查看两个键对应的值发现没有改变,这是因为事务并没有执行
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379>

案例三:一个出错,全不执行

使用命令MULTI开启事务,DISCARD放弃事务

# 开启事务
127.0.0.1:6379> MULTI
OK
# 两三个命令加入队列
127.0.0.1:6379(TX)> set k1 100
QUEUED
127.0.0.1:6379(TX)> set k2 200
QUEUED
# 让这个命令出现语法错误
127.0.0.1:6379(TX)> set k3
(error) ERR wrong number of arguments for 'set' command
# 执行事务,一个语法错误,redis直接返回错误,所有的命令都不会执行
127.0.0.1:6379(TX)> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379>
# 查看结果,并未改变
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379>

案例四:那个出错,那个不执行,其余正常执行

如下图,编译可以成功,但是exec执行的时候报错

Redis Transaction事务_Redis

案例四:watch监控

Redis使用Watch来提供乐观锁定,类似于CAS(Check-and-Set):

  • 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
  • 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。

在事务开启之前监听了某个 key,那么您不应该在事务中尝试修改它,否则会导致事务中断。watch命令是一种乐观锁的实现,Redis在修改的时候会检测数据是否被更改,如果更改了,则整个事务执行失败,下图第6步执行结果返回为空,也就是相当于是失败,案例说明(开启了两个客户端,模拟加塞的场景):

Redis Transaction事务_Redis_02

可以使用UNWATCH命令取消监听某key,如下:

# 取消监听
127.0.0.1:6379> UNWATCH
OK
127.0.0.1:6379>