Redis的事务控制

事务的基本概念

  • 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发来的命令请求打断。
  • 事务是一个原子操作:事务中的命令要么全部执行,要么全部不执行。

Redis事务相关的几个命令

  • multi:MULTI 命令用于开启一个事务,它总是返回 OK 。 MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC命令被调用时, 所有队列中的命令才会被执行。
  • exec :执行所有的事物命令,EXEC 命令的回复是一个数组, 数组中的每个元素都是执行事务中的命令所产生的回复。 其中, 回复元素的先后顺序和命令发送的先后顺序一致。 当客户端处于事务状态时, 所有传入的命令都会返回一个内容为 QUEUED 的状态回复(status reply), 这些被入队的命令将在 EXEC 命令被调用时执行。

  • discard: 通过调用 DISCARD , 客户端可以清空事务队列, 并放弃执行事务。

  • watch key [key ...]:监视一个或多个key(类似于乐观锁)
  • unwatch:取消watch对所有key的监视
Redis事务的三个阶段
  • 开始事务:使用multi命令开启一个事务,当一个事务被exec或discard后,改事务就宣告结束(无论有没有成功执行),下次在向开启事务就必须在使用这个命令开启事务。
  • 命令入队:简单点说就是,开启事务后输入的命令不会立即执行,而是先入队,执行当exec后在一次性执行。
  • 执行事务:使用exec命令执行事务

Redis事务使用示例: 1、正常执行

2、取消事务

3、事务在执行 EXEC 之前,入队的命令可能会出错(语法上就是错误的),执行exec时,整个事务都会失败。

       对于发生在 EXEC 执行之前的错误,客户端以前的做法是检查命令入队所得的返回值:如果命令入队时返回 QUEUED ,那么入队成功;否则,就是入队失败。如果有命令在入队时失败,那么大部分客户端都会停止并取消这个事务。        不过,从 Redis 2.6.5 开始,服务器会对命令入队失败的情况进行记录,并在客户端调用 EXEC 命令时,拒绝执行并自动放弃这个事务。

4、事命令可能在 EXEC 调用之后失败(语法上没有错误,但是调用执行的时候出错了),在执行exec命令时,其他正确的命令可以正确执行,错误命令抛出错误

为什么Redis不支持事务回滚?

通过上面的案例我们可以看到redis在事务中发生错误后是没有回滚的,而是继续执行余下的命令,那么redis为什么不支持事务回滚呢?从各方面考虑有以下两点原因:

  • Redis命令只会因为错误的语法而失败,或是命令用在了错误类型的键上面,也就是说,从实用的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发过程中别发现,而不应出现在生产环境中。而且需要注意的是在通常情况下, 回滚并不能解决编程错误带来的问题。
  • 因为redis不需要支持事务回滚,所以他可以在内部保持简单和快捷。

5、使用watch监控 WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败。下面使用很典型的账户和消费问题来展示一下watch的作用。 案例一:使用watch检测balance,事务期间balance数据未变动,事务执行成功

案例二:使用watch检测balance,在开启事务后(标注1处),在新窗口执行标注2中的操作,更改balance的值,模拟其他客户端在事务执行期间更改watch监控的数据,然后再执行标注1后命令,执行EXEC后,事务未成功执行。

留言区

还能输入500个字符