🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>[info] redis的事务其实并不满足原子性,仅仅是满足了隔离性。如果为了原子性需求,一般不使用redis的事务功能,而直接使用lua脚本结合。 [toc] ## 概述 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之后,会执行正确的语句,并跳过有不适当的语句.(由此可见,redis的事务其实不满足原子性) (如果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" ```