Redis支持简单的事务
Redis与 mysql事务的对比
Mysql |
Redis |
|
开启 |
start transaction |
multi |
语句 |
普通sql |
普通命令 |
失败 |
rollback 回滚 |
discard 取消(不叫回滚,是队列里面的命令不执行,队列里面的任务根本就没有执行。而不是执行了也可以撤回来) |
成功 |
commit |
exec |
注: rollback与discard 的区别 如果已经成功执行了2条语句, 第3条语句出错. Rollback后,前2条的语句影响消失. Discard只是结束本次事务,前2条语句造成的影响仍然还在。严格来讲不叫回滚,只是叫取消。Redis的事务相对要简单。 r1:2>set wang 100 "OK" r1:2>set zhao 100 "OK" r1:2>multi "OK" r1:2>decrby zhao 100 "QUEUED" //减100并没有执行,而是加入到了队列中,redis是单进程的,exec的时候就回去执行队列里面的语句 r1:2>incrby wang 100 "QUEUED" r1:2>get wang "QUEUED" r1:2>get zhao "QUEUED" r1:2>exec
注: 在mutil后面的语句中, 语句出错可能有2种情况 1: 语法就有问题, 这种,exec时,报错, 所有语句得不到执行 r1:2>multi "OK" r1:2>decrby zhao 100 "QUEUED" r1:2>sdsv "ERR unknown command 'sdsv'" r1:2>exec "EXECABORT Transaction discarded because of previous errors." //事务取消了,zhao没有减100 2: 语法本身没错,但适用对象有问题. 比如 zadd 操作list对象 Exec之后,会执行正确的语句,并跳过有不适当的语句. r1:2>multi "OK" r1:2>decrby zhao 100 "QUEUED" r1:2>sadd wang pig //wang是一个字符串,这里当成是集合在处理 "QUEUED" //放在队列里面,命令尚没有执行, r1:2>exec 1) "0" //zhao的钱变为了0 2) "WRONGTYPE Operation against a key holding the wrong kind of value" //第二个语句执行出错 (如果zadd操作list这种事怎么避免? 这一点,由程序员负责) Multi是把命令放在一个队列里面,exec是真正的执行,语法错误则都不执行,语法没错但是适用对象有错则执行正确的语句跳过错误的语句。这就没法保证原子性。 r1:2>multi "OK" r1:2>decrby zhao 100 "QUEUED" r1:2>decrby wang 100 "QUEUED" r1:2>discard //取消,就是清空队列,就不会执行了 "OK" r1:2>mget zhao wang 1) "100" 2) "100"
思考: 我正在买票 Ticket -1 , money -100 而票只有1张, 如果在我multi之后,和exec之前, 票被别人买了---即ticket变成0了. 我该如何观察这种情景,并不再提交 悲观的想法: 世界充满危险,肯定有人和我抢, 给 ticket上锁, 只有我能操作. [悲观锁] 乐观的想法: 没有那么人和我抢,因此,我只需要注意, --有没有人更改ticket的值就可以了 [乐观锁] Redis的事务中,启用的是乐观锁,只负责监测key没有被改动. 具体的命令---- 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 //现在已经对ticket进行了监控,另外一个窗口将ticket改动了 另一个窗口:> decr ticket redis 127.0.0.1:6379> exec (nil) // 返回nil,说明监视的ticket已经改动了,事务就取消了.队列就不执行了。 redis 127.0.0.1:6379>mget ticket money "0" "200" watch key1 key2 ... keyN 作用:监听key1 key2..keyN有没有变化,如果任意一个有变, 则事务取消 unwatch 作用: 取消所有watch监听