【Redis】深入理解 Redis 事务:命令、应用与实战案例
文章目录
- 一、Redis 事务
- 1. 什么是事务
- 2. 事务命令
- 1. MULTI - 开启事务
- 2. EXEC - 执行事务
- 3. DISCARD - 取消事务
- 4. WATCH - 监视键
- 5. UNWATCH - 取消监视
- 3. 实例场景演示
- 案例1:银行转账(使用WATCH实现乐观锁)
- 案例2:库存扣减(处理执行错误)
- 案例3:商品抢购(事务+过期时间)
一、Redis 事务
1. 什么是事务
Redis 的事务和 Mysql 的事务概念类似,即把一系列操作绑定成组,让这组操作能够批量执行。
区别主要体现在以下几个方面:
-
弱化的原子性:Redis 不支持回滚机制,只能批量执行命令,无法做到 “一个失败就恢复到初始状态”。也就是说,如果事务中的某个命令失败,Redis 无法自动撤销之前的操作。
-
不保证一致性:Redis 事务没有约束条件和回滚机制,因此不能确保事务前后数据的一致性。MySQL 的一致性保证的是在事务执行前后,结果是有效且合理的,避免出现非法状态。
-
不需要隔离性:Redis 不支持事务隔离级别,因为它是单线程处理请求的,不会出现并发事务执行的情况。
-
不需要持久性:Redis 数据是保存在内存中的,是否开启持久化与事务无关,完全由
redis-server
配置决定。
Redis 事务本质上是通过维护一个 事务队列 实现的。客户端每次在事务中执行操作时,会将命令发送到服务器并加入事务队列,但命令不会立即执行。只有在收到 EXEC
命令时,所有操作才会按顺序执行。
因此,Redis 的事务功能相比 MySQL 要弱得多,只能保证事务中的操作按顺序执行,不会被其他客户端的命令插队。
2. 事务命令
Redis 的事务命令具体如下:
命令 | 功能描述 |
---|---|
MULTI | 标记事务开始 |
EXEC | 执行事务中的所有命令 |
DISCARD | 取消事务,放弃所有命令 |
WATCH | 监视键,实现乐观锁 |
UNWATCH | 取消所有 WATCH 的键监视 |
下面具体介绍每个命令的作用与实例:
1. MULTI - 开启事务
功能:标记事务块的开始
语法:MULTI
特点:后续命令将进入队列,直到执行EXEC
实例:
redis> MULTI
OK
redis> SET user:100 "Alice"
QUEUED
redis> INCR counter
QUEUED
2. EXEC - 执行事务
功能:执行所有事务块内的命令
语法:EXEC
返回值:按顺序返回各命令的执行结果
实例(接上例):
redis> EXEC
1) OK # SET命令结果
2) (integer) 3 # INCR命令结果
3. DISCARD - 取消事务
功能:放弃所有已入队的命令
语法:DISCARD
实例:
redis> MULTI
OK
redis> SET temp "value"
QUEUED
redis> DISCARD
OK
redis> GET temp # 命令未执行
(nil)
4. WATCH - 监视键
功能:监视键的CAS操作(Check-And-Set)
语法:WATCH key [key ...]
特点:如果被监视键在EXEC前被修改,则事务失败
实例:
# 终端1
redis> WATCH account:100
OK
redis> MULTI
OK
redis> GET account:100
QUEUED# 终端2(同时操作)
redis> SET account:100 "modified"# 终端1继续
redis> EXEC # 返回nil表示执行失败
(nil)
5. UNWATCH - 取消监视
功能:取消所有WATCH的键监视
语法:UNWATCH
实例:
redis> WATCH key1 key2
OK
redis> UNWATCH
OK
3. 实例场景演示
案例1:银行转账(使用WATCH实现乐观锁)
# 初始化数据
redis> SET account:A 1000
OK
redis> SET account:B 500
OK# 转账事务
redis> WATCH account:A account:B # 监视账户
OK
redis> MULTI
OK
redis> DECRBY account:A 200 # A账户减200
QUEUED
redis> INCRBY account:B 200 # B账户加200
QUEUED
redis> EXEC
1) (integer) 800 # account:A新值
2) (integer) 700 # account:B新值
案例2:库存扣减(处理执行错误)
redis> SET inventory "10"
OK
redis> MULTI
OK
redis> DECR inventory # 正常命令
QUEUED
redis> INCRBY inventory "abc" # 错误命令(非数字)
QUEUED
redis> GET inventory # 正常命令
QUEUED
redis> EXEC
1) (integer) 9 # DECR执行成功
2) (error) ERR value is not an integer or out of range
3) "9" # GET执行成功
案例3:商品抢购(事务+过期时间)
# 商品初始库存100,有效期10秒
redis> SET item:123:stock 100 EX 10
OKredis> WATCH item:123:stock
OK
redis> MULTI
OK
redis> DECR item:123:stock
QUEUED
redis> EXEC # 返回剩余库存
(integer) 99