图解

image.png
Redis的事务采用标记来实现的,如下所示

  1. public class Test {
  2. private static final int SHA_DOU_BU_SHI = 0;
  3. private static final int FEI_WU = 1 << 1;
  4. private static final int LA_JI = 1 << 2;
  5. private static final int LE_SE = 1 << 3;
  6. public static void main(String[] args) {
  7. fnm();
  8. }
  9. public static void fnm() {
  10. int flags = 0;
  11. flags |= LA_JI;
  12. flags |= FEI_WU;
  13. flags |= LE_SE;
  14. if ((flags & FEI_WU) == FEI_WU) {
  15. System.out.println("废物标签🏷️");
  16. }
  17. if ((flags & LA_JI) == LA_JI) {
  18. System.out.println("垃圾标签🏷️");
  19. }
  20. if ((flags & LE_SE) == LE_SE) {
  21. System.out.println("LE_SE标签🏷️");
  22. }
  23. if ((flags & SHA_DOU_BU_SHI) == 1) {
  24. System.out.println("啥都不是标签🏷️");
  25. }
  26. }
  27. }
  • Multi进入事务为client打上 CLIENT_MULTI: This client is in a MULTI context
  • watch的key发生了变更,为client打上 CLIENT_DIRTY_CAS: Watched keys modified. EXEC will fail.
  • queue失败打上 CLIENT_DIRTY_EXEC: EXEC will fail for errors while queueing

    事务

事务的特性: ACID

  • A: 原子性(像单个命令一样,要么执行要么不执行,执行失败也是执行)
  • C:一致性(数据从一个状态变成另外一个状态,Redis执行成功就会修改状态,失败就不会更新状态)
  • I : 隔离型(Redis是单线程执行command,没有竞争条件,本书就是隔离的)
  • D: 持久性 (有AOF和RDB保证)

    由于Redis并未实现回滚,所以在一个事务中执行完成的命令不会因为后边的错误而回滚,从这个角度可以说是没有实现ACID中的一致性

    Redis does not support rollbacks of transactions since supporting rollbacks would have a significant impact on the simplicity and performance of Redis.

使用

  1. Redis事务使用 `Multi` 命令进入一个事务,虽然客户端提交的多个命令都会进入 `队列`,调用 `Exec` 命令的时候执行所有提交的 `Command`,调用 `Discard`则会清空事务队列,也就是 `multiState->commands`这部分,然后退出事务。
  1. > MULTI
  2. OK
  3. > INCR foo
  4. QUEUED
  5. > INCR bar
  6. QUEUED
  7. > EXEC
  8. 1) (integer) 1
  9. 2) (integer) 1

事务中的错误

Redis事务运行期间,可能出现两种类型的错误

  • 执行的命令进入队列失败,例如参数错误,例如服务器内存限制导致导致命令不能进入队列。
  • 命令执行失败,例如字符串的key用了集合的命令

执行事务

image.png

Redis持久化和事务

持久化得分开讨论

  • 持久化选项没开,GG
  • 用的RDB,这个不会,因为持久化函数执行的时候是直接持久化的dbNum,而事务的state是挂载在client上的。从另外一个角度来说,RDB是快照,后边exec命令可能丢失,重放失败(aof同样存在这个问题,需要使用工具check)
  • aof,执行aofrewrite的时候同rdb,只是将dbNum里边的数据转成redis protocol的形式,只有在执行的时候exec命令的时候写入到aof缓冲区。首先构建一个multi命令写入,然后每次执行命令的时候构建一个写入aof,最后补充一个exec命令。

    Redis脚本和事务

Redis脚本也是事务性质的,所有能够在Redis 事务中完成的,同样也可以使用脚本,一般来说,使用脚本比事务更加简单,也更快.

Reference