redis专题9事务

29次阅读

共计 1333 个字符,预计需要花费 4 分钟才能阅读完成。

[info] 仅做了解一般不用,更多是通过 lua 来解决原子性问题。

Redis 支持简单的事务,所谓简单是因为其不支持回滚(回滚是用队列模仿的),与 mysql 有以下区别

type mysql redis
开启 start transaction muitl
语句 普通 sql 普通命令
失败 rollback 回滚 discard 取消
成功 commit exec

rollback 与 discard 的区别:
如果已经成功执行了 2 条语句, 第 3 条语句出错
Rollback 后, 前 2 条的语句影响消失。
discard 只是取消队列,并非回滚。要用在 exec 前面;

在 mutil 后面的语句中, 语句出错可能有 2 种情况:

1: 语法就有问题,
这种,exec 时, 报错, 所有语句得不到执行

2: 语法本身没错, 但适用对象有问题. 比如 zadd 操作 list 对象
Exec 之后, 会执行正确的语句, 并跳过有不适当的语句.
(如果 zadd 操作 list 这种事怎么避免? 这一点, 由程序员负责)

Example

127.0.0.1:6379> multi #开启事务
OK

127.0.0.1:6379> decrby zz 100
QUEUED

127.0.0.1:6379> incrby xx 100
QUEUED

127.0.0.1:6379> exec
1) (integer) 900
2) (integer) 900

127.0.0.1:6379> multi
OK

127.0.0.1:6379> decrby zz 100
QUEUED

127.0.0.1:6379> sadd zz haha #语法本身没有错, 那整个事务中的语句都会执行;
QUEUED

127.0.0.1:6379> exec
1) (integer) 800 
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value

悲观锁与乐观锁

场景如下:

我正在买票
Ticket -1 , money -100
而票只有 1 张, 如果在我 multi 之后, 和 exec 之前, 票被别人买了 — 即 ticket 变成 0 了.
我该如何观察这种情景, 并不再提交

  • 悲观的想法: 世界充满危险, 肯定有人和我抢, 给 ticket 上锁, 只有我能操作. [悲观锁]
  • 乐观的想法: 没有那么多人和我抢, 因此, 我只需要注意, 在下单之前看看有没有人更改 ticket 的值就可以了 [乐观锁]

Redis 的事务中, 启用的是乐观锁, 只负责监测 key 没有被改动. 具体的命令:watch 命令

watch key1 key2  ... keyN

作用: 监听 key1 key2..keyN 有没有变化, 如果有变, 则事务取消

unwatch 

作用: 取消所有 watch 监听

redis 127.0.0.1:6379> watch ticket
OK
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> decr ticket
QUEUED
redis 127.0.0.1:6379> decrby money 100
QUEUED
redis 127.0.0.1:6379> exec #在 exec 之前该数据在其他 session 有改动就取消事务, 返回 nil
(nil)  
redis 127.0.0.1:6379> get ticket
"0"
redis 127.0.0.1:6379> get money
"200"

正文完
 0