Redis进阶(二)—— Redis 事务

2. Redis事务

2.1 Redis 事务 和 MySQL 事务区别

Redis 事务 和 MySQL 事务概念上类似,都是指 把一系列操作在一起执行,不允许中间插入。

Redis 事务特点:

  • 弱原子性 或 无原子性:redis 没有回滚机制,只是批量一起执行,里面有失败就是失败了。
  • 不保证一致性:redis 不涉及约束,没有回滚。前后结果不都合理有效,可能有非法中间态。
  • 不需要保隔离性:没有隔离级别,因为不会并发执行事务(redis 单线程处理请求)
  • 不需持久性:存在内存里,是否开启持久,是配置的问题,和事务无关。

Redis 事务本质上,是客户端上有一个 "事务队列",每次客户端开启事务,命令先存到队列中,服务器收到 exec 命令,按顺序执行队列中的操作。

2.2 使用场景示例

Redis 事务,主要就是避免其他客户端命令插队执行,将操作打包执行。

如:秒杀活动

一个经典写法:

bash 复制代码
//获取仓库剩余商品个数
if(个数 > 0) {
	下单成功
	个数减一;	
}

如果不加锁,就存在 "线程安全" 问题,在 Redis 使用事务来解决。

redis 原生命令中不支持类似上面的条件判断,但是 redis 支持 lua 脚本,通过 lua 脚本就可以实现,且和 redis 事务一样是打包批量执行。

2.3 使用事务

redis 中通过 MULTI 开启事务,EXEC 执行事务, DISCARD 放弃当前事务。

开启事务后,先放入事务队列,此时没有执行事务,在其他客户端上是看不到这几个键的。

执行 EXEC ,

这时,这几个键才真正放入 redis 中,同时在 新窗口中也可查询到。

如果,事务结束前,出现了服务器重启等情况,就相当于是 DISCARD 。

下面讲一种情况,key 的值初始为 111,客户端1 开启了事务,并将 key 设为 222,但是在客1事务执行前,客户端2 将 key 设为了 333。虽然,从顺序上看,客1 是先设置的 key 为 222,但实际 set key 222 执行的晚,结果为 222。

为此,redis 中有 WATCH 命令可以监视某个或某些 key 在事务执行前是否发生了变化。

客户端1 设置 key1 为 222,但未执行。客户端2 设置 key1 为 .

666。

客户端1 执行事务

由于 key1 在事务执行前发生了改变,所以返回了 nil 没有执行。

2.4 WATCH 的实现原理

watch 的实现,类似于 "乐观锁"。

乐观锁 是一类锁的特质,即加锁前,预期锁冲突几率比较低,先不加锁。冲突真正发生再加锁。

想要看 乐观锁 的更细节讲述,可看此文章:多线程进阶

redis 的 watch 基于版本号这样的机制,来实现了 "乐观锁"。

watch key 的时候,会给 key 安排一个 版本号,给 exec 加了一个判定条件,每次修改 key 都会引起版本号变化,当执行 EXEC 时,就会进行判定,版本号不一致说明 key 被修改过,就丢弃该操作,返回 nil;反之,未被修改,进行真正执行。

相关推荐
Franciz小测测15 分钟前
MySQL 增量备份实践:文件都在,为什么仍可能恢复失败?
数据库·mysql·binlog
IT规划师19 分钟前
Redis 数据类型全解 - ZSet:两个编码,七种玩法(五)
redis·.net
2401_891409263 小时前
量化数据13:港股分钟K线、Level2逐笔Tick、十档盘口和港股通历史数据的批量提取
数据库
w-w0w-w9 小时前
SQL注入
网络·数据库·sql
tianyuanwo9 小时前
NetBox 数据库详解:当“关系型数据库”被装进一个网络运维的领域模型里
运维·数据库·netbox
一条泥憨鱼9 小时前
【计算机网络】短连接、长连接与连接池:从 TCP 握手到池化复用的完整链路
网络·数据库·网络协议·tcp/ip·计算机网络
我不会起名字32210 小时前
Redis 从 0 到 1(十七):订单 30 分钟不支付自动关闭——ZSet 延迟队列 Go 实现
redis·go·延迟队列·zset·订单
IvorySQL10 小时前
深入 PostgreSQL WAL:从崩溃恢复到逻辑复制
数据库·postgresql
利威尔xu10 小时前
Go IM 源码实战(14):本地缓存快 3000 倍,失效却难 10 倍
后端·缓存·微服务·面试·golang
幽灵诶11 小时前
Mysql(基于测试的学习)
数据库·mysql