说说 Redis 事务

更多技术文章,请关注我的个人博客 www.immaxfang.com 和小公众号 Max的学习札记
Redis 事务简介Redis 只是提供了简单的事务功能 。其本质是一组命令的集合,事务支持一次执行多个命令,在事务执行过程中,会顺序执行队列中的命令,其他客户端提交的命令请求不会插入到本事务执行命令序列中 。命令的执行过程是顺序执行的,但不能保证原子性 。无法像 MySQL 那样,有隔离级别 , 出了问题之后还能回滚数据等高级操作 。后面会详细分析 。
Redis 事务基本指令Redis 提供了如下几个事务相关的基础指令 。
  • MULTI开启事务,Redis 会将后续命令加到队列中,而不真正执行它们,直到后续使用EXEC来原子化的顺序执行这些命令
  • EXEC执行所有事务块内的命令
  • DISCARD取消事务,放弃执行事务块内所有的命令
  • WATCH监视一个或多个 key,若事务在执行前,这些 key 被其他命令修改,则事务被终端,不会执行事务中的任何命令
  • UNWATCH取消 WATCH命令对所有 keys 的监视
一般情况下,一个简单的 Redis 事务主要分为如下几个部分:
  1. 执行命令MULTI开启一个事务 。
  2. 开启事务之后,执行命令的多个命令会依次被放入一个队列,放入成功则会返回QUEUED消息 。
  3. 执行命令EXEC提交事务,Redis 会依次执行队列中的命令,并依次返回所有命令的结果 。(若想放弃提交事务,则执行DISCARD) 。
下图简单介绍了下 Redis 事务执行的过程:
说说 Redis 事务

文章插图
实例分析下面我们来通过一些实际具体例子,来体会下 Redis 中的事务 。前面我们也说到 Redis 的事务不是正真的事务,是无法完全满足标准事务的ACID特性的 。通过下面的例子,我们来看看,Redis 的“破产版”事务到底存在什么问题 。
  • [A]正常执行提交
【说说 Redis 事务】127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET a 1QUEUED127.0.0.1:6379> SET b 2QUEUED127.0.0.1:6379> EXEC1) OK2) OK127.0.0.1:6379> GET a"1"127.0.0.1:6379> GET b"2"开启事务后,提交的命令都会加入队列(QUEUED),执行 EXEC 后会逐步执行命令并返回结果 。这个看起来是不是和我们平时使用 MySQL 的事务操作相似,类似 start transaction 和 commit 。
  • [B]正常取消事务
127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET a 1QUEUED127.0.0.1:6379> SET b 2QUEUED127.0.0.1:6379> DISCARDOK127.0.0.1:6379>127.0.0.1:6379> GET a(nil)127.0.0.1:6379> GET b(nil)开启事务后,若不想继续事务 , 使用 DISCARD 取消,前面提交的命令并不会真正执行,相关的 key 值不变 。这个看起来也和 MySQL 的事务相似,类似 start transaction 和 rollback 。
  • [C]WATCH 监视 key
-- 线程 1 中执行127.0.0.1:6379> del a(integer) 1127.0.0.1:6379> get a(nil)127.0.0.1:6379> SET a 0OK127.0.0.1:6379> WATCH aOK127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET a 1QUEUED----------------------------------------- 线程 2 中执行----------------------------------------- 127.0.0.1:6379> SET a 2----------------------------------------- OK127.0.0.1:6379> EXEC(nil)127.0.0.1:6379> GET a"2"在开启事务之前 WATCH 了 a 的值,随后再开启事务 。在另一个线程中设置了 a 的值(SET a 2),然后再 EXEC 执行事务,结果为 nil,说明事务没有被执行 。因为 a 的值在 WATCH 之后发生了变化,所以事务被取消了 。
需要注意的是,这里和开启事务的时间点没有关系,与 MULTI 和另一个线程设置 a 的值的先后没有关系 。只要是在 WATCH 之后发生了变化 。无论事务是否已经开启,执行事务(EXEC)的时候都会取消 。普通情况下,在执行 EXEC 和 DISCARD 命令时,都会默认执行 UNWATCH 。

推荐阅读