万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • Redis

    • Redis简介
    • 缓存的认识
    • Linux安装Redis的正确方式
    • Redis数据类型
    • Redis底层数据结构
    • Redis回收策略与缓存过期
    • Redis持久化
    • Redis发布与订阅
    • Redis事务
      • 事物命令
      • 事务机制
    • Redis Lua脚本
    • Redis 慢查询
    • Redis 监视器
    • Redis通讯协议
    • Redis事件处理机制与NIO演进
    • Redis 常用命令
    • Redis与MyBatis整合
    • Spring、SpringBoot整合Redis
  • 集群架构

  • Redis
  • Redis
2022-03-30
目录

Redis事务

# Redis事务

  • Redis 事务 (opens new window):将一组命令放在同一个事务中进行处理。
  • Redis的事务是通过multi、exec、discard和watch这四个命令来完成的。
  • Redis的单个命令都是原子性的,所以Redis的事务性的对象是命令集合,即一次执行多个命令。
  • Redis会将命令集合序列化并确保处于同一事务的命令集合连续(按顺序地执行)且不被打断的执行。
  • Reids的事物是弱事物,并不支持回滚。

# 事物命令

详细指令看:help @transactions

  • multi:用于标记事务块的开始,Redis会将后续的命令逐个放入队列中,然后使用exec原子化地执行这个命令队列。
  • exec:执行MULTI后发出的所有命令(执行命令队列)
  • discard:清除MULTI后发出的所有命令(清除命令队列)
  • watch:观察给定的key以确定MULTI/EXEC块的执行
  • unwatch:清除监视的key

示例:

# 执行过程成功
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 123
QUEUED
127.0.0.1:6379> hset user:1 name zhansan
QUEUED
127.0.0.1:6379> exec
1) OK
2) (integer) 1

# 执行失败
127.0.0.1:6379> watch k1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> hset user:1 name wangwu
QUEUED
127.0.0.1:6379> exec # 在提交前,在另个客户端更改了k1的值
(nil)
127.0.0.1:6379> hget user:1 name
"zhansan"

# 事务机制

# 事务的执行

  • 事务开始:在RedisClient中,有个flags属性,用来表示是否在事务中,flags=REDIS_MULTI
  • 命令入队:RedisClient将命令存放在事务队列中(EXEC,DISCARD,WATCH,MULTI除外)
  • 事务队列:multiCmd *commands 用于存放执行的命令
  • 执行事务:RedisClient向服务器端发送exec命令,RedisServer会遍历事务队列,执行队列中的命令,最后将执 行的结果一次性返回给客户端。

如果某条命令在入队过程中发生错误,redisClient将flags置为REDIS_DIRTY_EXEC,EXEC命令将会失败返回。

127.0.0.1:6379> hset user:1
(error) ERR wrong number of arguments for 'hset' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

RedisClient源码结构体定义:

typedef struct redisClient{ 
  int flags // 状态
  multiState mstate; // 事务状态
  // ..... 
}redisClient; 

// 事务状态 
typedef struct multiState{ 
  multiCmd *commands; // 事务队列,FIFO顺序 是一个数组,先入队的命令在前,后入队在后 
  int count; // 已入队命令数 
}multiState; 

// 事务队列 
typedef struct multiCmd{ 
  robj **argv; // 参数 
  int argc; // 参数数量 
  struct redisCommand *cmd; // 命令指针 
}multiCmd;

# Watch的执行

watch命令用来监视数据库键,在发起执行事物的时候,如果这个键没有被更改,那么事物就会执行。

redisDb有一个watched_keys字典,key是某个被监视的数据的key,value是一个链表,记录了所有监视这个数 据的客户端。

当修改这个key数据后,监视这个数据的客户端的flags置为REDIS_DIRTY_CAS。此时,RedisClient向服务器端发送exec命令,服务器判断RedisClient的flags,如果为REDIS_DIRTY_CAS,则清空事务队列。

typedef struct redisDb{ 
  // ..... 
  dict *watched_keys; // 正在被WATCH命令监视的键 
  // ..... 
}redisDb;

# Redis的弱事务性

为什么说Redis是弱事物性?

  • 事物中指令入队过程中,发现语法错误(flags=multi_dirty),会清空命令队列,而不是依次回滚。

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set k1 lisi
    QUEUED
    127.0.0.1:6379> hset user:1 
    (error) ERR wrong number of arguments for 'hset' command  # 语法不能是错误的
    127.0.0.1:6379> exec
    (error) EXECABORT Transaction discarded because of previous errors.
    
    
  • 不支持回滚。官方对于不支持回滚的原因如下:

    • 大多数事务失败是因为语法错误或者类型错误,这两种错误,在开发阶段都是可以预见的
    • Redis为了性能方面就忽略了事务回滚。
上次更新: 5/30/2023, 11:42:20 PM
Redis Lua脚本

Redis Lua脚本→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式