Redis(四):事务

目录

  • Redis(四):事务
  • redis 事务的相关命令
  • 执行情况
  • 全部执行
  • 全部放弃
  • 全体连坐
  • 冤头债主
  • WATCH与乐观锁

redis 事务的相关命令

https://www.redis.net.cn/order/3639.html

序号

命令及描述

1

DISCARD 取消事务,放弃执行事务块内的所有命令。

2

EXEC 执行所有事务块内的命令。

3

MULTI 标记一个事务块的开始。

4

UNWATCH 取消 WATCH 命令对所有 key 的监视。

5

[WATCH key key ...] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

返回值:事务块内所有命令的返回值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil

执行情况

Redis不是强一致性

  • EXEC:全部执行
  • DISCARD:全部放弃
  • EXEC前就有ERR:全体连坐
  • EXEC后运行ERR:对的执行,错的不执行

http://c.biancheng.net/view/4541.html

全部执行

expire设置 redis redis exec_expire设置 redis

全部放弃

expire设置 redis redis exec_expire设置 redis_02

全体连坐

一个事务ERROR,全部都不执行

类似Java编译异常

expire设置 redis redis exec_Redis_03

冤头债主

对的执行,错的抛出

类似Java运行异常

expire设置 redis redis exec_EXEC_04

WATCH与乐观锁

当 Redis 使用 exec 命令执行事务的时候,它首先会去比对被 watch 命令所监控的键值对

  • 如果没有发生变化,那么它会执行事务队列中的命令,提交事务
  • 如果发生变化,那么它不会执行任何事务中的命令,而去事务回滚。

注:这里的变化指的是与WATCH指令执行时的值相比,而不是说事务不能改变监控的值

无论事务是否回滚,Redis 都会去取消执行事务前的 watch 命令,这个过程如图所示。

expire设置 redis redis exec_业务逻辑_05

例子:

expire设置 redis redis exec_业务逻辑_06

Redis 参考了多线程中使用的 CAS(比较与交换,Compare And Swap)去执行的。在数据高并发环境的操作中,我们把这样的一个机制称为乐观锁。这句话还是比较抽象,也不好理解。

所以先简要论述其操作的过程,当一条线程去执行某些业务逻辑,但是这些业务逻辑操作的数据可能被其他线程共享了,这样会引发多线程中数据不一致的情况。

为了克服这个问题,首先,在线程开始时读取这些多线程共享的数据,并将其保存到当前进程的副本中,我们称为旧值(old value),watch 命令就是这样的一个功能。

然后,开启线程业务逻辑,由 multi 命令提供这一功能。在执行更新前,比较当前线程副本保存的旧值和当前线程共享的值是否一致,如果不一致,那么该数据已经被其他线程操作过,此次更新失败。

为了保持一致,线程就不去更新任何值,而将事务回滚;否则就认为它没有被其他线程操作过,执行对应的业务逻辑,exec 命令就是执行“类似”这样的一个功能。

注意,“类似”这个字眼,因为不完全是,原因是 CAS 原理会产生 ABA 问题。所谓 ABA 问题来自于 CAS 原理的一个设计缺陷,它可能引发 ABA 问题,如表 1 所示。

时间顺序

线程1

线程2

说明

T1

X=A


线程 1 加入监控 X

T2

复杂运算开始

修改 X=B

线程 2 修改 X,此刻为 B

T3

处理简单业务


T4

修改 X=A

线程 2 修改 X,此刻又变回 A

T5

结束线程 2

线程 2 结束

T6

检测X=A,验证通过,提交事务


CAS 原理检测通过,因为和旧值保持一致