47 redis事务之理论简介
什么是事务
可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入
能干什么?
一个队列中,一次性、顺序性、排他性的执行一系列操作
redis事务vs数据库事务
1 单独的隔离操作
Redis的事务仅仅是保证事务里的操作会被连续独占的执行,++redis命令执行是单线程架构++,在执行完事务内所有指令前是不可能再去同时执行其他客户端的请求的
2 没有隔离级别的概念
因为事务提交前任何指令都不会被实际执行【只是放在队列里面不会执行】,也就不存在"事务内的查询要看到事务里的更新,在事务外查询不能看到"这种问题了
3不保证原子性
Redis的事务不保证原子性,也就是不保证所有指令同时成功或同时失败,只有决定是否开始执行全部指令的能力,没有执行到一半进行回滚的能力
4 排它性
Redis会保证一个事务内的命令依次执行,而不会被其它命令插入
48 redis事务之案例实操
Redis 事务是通过 MULTI
命令进入的。该命令始终返回 OK
。此时,用户可以发送多个命令,但 Redis 不会立即执行这些命令,而是将它们排入队列中。所有命令会在调用 EXEC
命令后一次性执行。
如果调用 DISCARD
命令,则会清空事务队列并退出事务
redis事务命令
1.DISCARD 取消事务→放弃执行事务块内的所有命令。
2.EXEC 执行所有事务块内的参令。
3.MULTI 标记一个事务块的开始。
4.UNWATCH 取消WATCH 命令对所有key的监视,
5.WATCH key [key .. ] 监视一个(或多个)key,如果在事劳执行之前这个(或这些)key被其他命令所改动,那么事务将被打断。
CASE1:正常执行
MULTI 和 EXEC

CASE2:放弃事务
MULTI 和 DISCARD

CASE3:全体连坐
一条命令出错,就全部放弃执行
127.0. 0.1:6379> MULTI
OK
- 1: 6379(TX)> set k1 v111
QUEUED
127.0. 0. 1: 6379( TX)> set k2 v222
QUEUED
127.0.0.1:6379(TX)> set k3 // 这个命令本身就是错误的
(error) ERR wrong number of arguments for 'set' command
- 1: 6379( TX) >
- 1: 6379( TX) > EXEC
EXECABORT Transaction discarded because of previous errors. //事务队列中的所有命令都不执行
事务中的错误
在事务过程中,可能会遇到两类命令错误:
-
命令在排队阶段失败 :也就是说,在调用
EXEC
之前就发生了错误。例如,命令可能存在语法错误(参数数量错误、命令名称错误等),或者遇到某些关键问题,如内存不足(例如服务器配置了maxmemory
指令设置了内存上限)。- 这种情况只能全部命令都放弃执行
-
命令在
EXEC
后执行时失败:例如,对某个键执行了不适用的操作(比如对一个字符串类型的键执行列表操作)。
CASE4:冤头债主
在执行 EXEC
之后发生的错误不会被特殊处理:即使事务中的某个命令执行失败,其他命令仍然会被继续执行。
总结:对的放行,错的不执行
补充:redis不提供事务回滚的功能,开发者必须在事务执行出错后,自行恢复数据库状态。
INCR email命令错误:邮箱是字符串不可能自增

CASE5:watch监控
redis的watch类似于乐观锁的设定,类似于CAS
悲观锁是一种假设"总会发生冲突"的锁机制。假设每次访问数据都是对数据进行修改。因此在对数据进行操作前,会先加锁,防止其他线程同时访问,以确保数据安全。
乐观锁假设"并发冲突是少数",所以**不加锁。**假设每次访问数据都不会修改数据。因此在更新数据时才校验数据是否被其他线程修改。
CAS 是一种无锁的原子操作,全称是 比较并交换。它是乐观锁的具体实现方式之一,底层依赖于 CPU 的原子指令。
工作原理:
-
先读取变量的旧值
-
和预期值进行比较
-
如果相等,则更新为新值
-
如果不等,说明有其他线程修改过,则重试或失败
watch
初始化k1和balance两个key,先监控再开启multi,保证两key变动在同一个事务内
- 1:6379> set k1 abc
OK
- 1: 6379> set balance 100
OK
- 1:6379>
- 1: 6379> WATCH balance
OK
127.0. 0.1:6379>
- 1: 6379> MULTI
OK
- 1: 6379( TX) > set k1 abc2
QUEUED
- 1: 6379( TX) > set balance 110
QUEUED
- 1: 6379( TX) > EXEC
OK
OK
127.0. 0. 1:6379> get k1
"abc2"
有加塞篡改:
客户端1监控了balance
客户端2修改了balance
客户端1的事务执行失败返回空

unwatch
UNWATCH
用于 取消之前通过 WATCH
命令监视的所有键,避免这些键的变动影响事务的执行。
-
在你使用
WATCH
命令监控某些键的变化时,如果你不再想基于这些键判断是否执行事务 ,就可以用UNWATCH
来取消。 -
如果你调用了
DISCARD
,Redis 会自动UNWATCH
,无需手动取消。
WATCH mykey
GET mykey
UNWATCH # 取消监视
MULTI
SET mykey "newvalue"
EXEC
小结
一旦执行了exec之前加的监控锁都会被去掉。
当客户端连接丢失【比如退出连接】,所有东西都会被取消监视