Loading

Redis(四):事务

Redis(四):事务

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

全部执行

image-20210303170216997

全部放弃

image-20210303170246203

全体连坐

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

类似Java编译异常

image-20210303170452173

冤头债主

对的执行,错的抛出

类似Java运行异常

image-20210303170731078

WATCH与乐观锁

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

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

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

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

image-20210303172008656

例子:

image-20210303172146900

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 原理检测通过,因为和旧值保持一致
posted @ 2021-03-09 16:42  cpaulyz  阅读(82)  评论(0编辑  收藏  举报