返回 Redis-事...... 登陆

Redis-事务即简单锁应用

阿神 2016-11-09 14:03:27 481

Redis支持简单的事务, Redis允许一组命令在单一步骤中执行, 事务有两个属性

一个事务从开始到执行会经历三个阶段

redis 与 mysql 事务的对比:

7.png

注: rollback 与 discard 的区别
如果已经成功执行了2条语句, 第3条语句出错
rollback后, 前两条语句影响消失
discard只是结束本次事务, 前两条语句造成的影响依然存在
注:
在multi后面的语句中, 语句出错可能有2种情况

使用redis模拟银行转账操作:

127.0.0.1:6379> set wang 200    #wang有200
OK
127.0.0.1:6379> set zhao 700    #zhao有700
OK
127.0.0.1:6379> 
127.0.0.1:6379> multi    #开启事务
OK
127.0.0.1:6379> decrby zhao 100    #zhao减100
QUEUED
127.0.0.1:6379> incrby wang 100    #wang加100
QUEUED
#以上两个QUEUED表示两条语句被放在队列里面, exec前并没有执行
127.0.0.1:6379> exec    #执行完毕
1) (integer) 600
2) (integer) 300
127.0.0.1:6379>
127.0.0.1:6379> multi    开启事务
OK
127.0.0.1:6379> 
127.0.0.1:6379> decrby zhao 100    #zhao减100
QUEUED
127.0.0.1:6379> das    #输入一个错误的命令
(error) ERR unknown command 'das'
127.0.0.1:6379> exec    #执行, 提示被忽略
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> 
127.0.0.1:6379> mget zhao wang    #zhao 和 wang的值不变
1) "600"
2) "300"
127.0.0.1:6379>
127.0.0.1:6379> multi
OK
127.0.0.1:6379> 
127.0.0.1:6379> decrby zhao 100    #zhao减100
QUEUED
127.0.0.1:6379> sadd wang pig    #故意把wang当做数组加入一个key, 发现并没有报错, 
#因为这条语句被存放在队列里, 并没有被执行
QUEUED
127.0.0.1:6379> exec    #此时语句才被执行, 所以报错, 但是zhao依然减了100, 说明执行了正确的语句, 跳过了不正取的语句, 影响还在
1) (integer) 500
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> 
127.0.0.1:6379> mget zhao wang 
1) "500"
2) "300"
127.0.0.1:6379>
127.0.0.1:6379> mget wang zhao
1) "400"
2) "400"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby zhao 100
QUEUED
127.0.0.1:6379> incrby wang 100
QUEUED
127.0.0.1:6379> 
127.0.0.1:6379> discard    #取消后值没变
OK
127.0.0.1:6379> 
127.0.0.1:6379> mget wang zhao
1) "400"
2) "400"
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI
127.0.0.1:6379>
127.0.0.1:6379> mget zhao wang
1) "400"
2) "400"
127.0.0.1:6379> 
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby zhao 100
QUEUED
127.0.0.1:6379> sadd wang pig
QUEUED
127.0.0.1:6379> 
127.0.0.1:6379> exec
1) (integer) 300
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> 
127.0.0.1:6379> discard    #不能discard
(error) ERR DISCARD without MULTI
127.0.0.1:6379> 
127.0.0.1:6379> mget zhao wang
1) "300"
2) "400"
127.0.0.1:6379>

watch key1 key2 ... keyN

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

unwatch(不加key): 取消所有 watch 监听

场景: 一个人正在买票, ticket-1, money-100, 而票只有一张, 如果在我multi之后, exec之前票被别人买走, 即ticket变为0了, 怎么办?

127.0.0.1:6379> set ticket 1    #加入只有1张票
OK
127.0.0.1:6379> set lisi 300    #lisi有300
OK
127.0.0.1:6379> set wang 300    #wang有300
OK
127.0.0.1:6379> 
127.0.0.1:6379> multi    #开启事务
OK
127.0.0.1:6379> decr ticket    #票数-1
QUEUED
127.0.0.1:6379> decrby lisi 100    #lisi准备买-100
QUEUED
127.0.0.1:6379> #此处还没有exec

假如就在exec前票被别人买走, 打开另一个终端

127.0.0.1:6379> decr ticket    #票-1
(integer) 0
127.0.0.1:6379> get ticket    #此时票数为0
"0"
127.0.0.1:6379>

此时提交lisi

127.0.0.1:6379> exec
1) (integer) -1    #票变为-1
2) (integer) 200    #钱-100
127.0.0.1:6379>

因此上面的过程不合理

要解决上面的情况,要采用监视

127.0.0.1:6379> set ticket 1    #票数为1
OK
127.0.0.1:6379> set lisi 200    #lisi钱是100
OK
127.0.0.1:6379> set wang 300    #wang是300
OK
127.0.0.1:6379> 
127.0.0.1:6379> watch ticket    #监控ticket有没有变动, 有变动的话则事务取消
OK
127.0.0.1:6379> multi    #开启事务
OK
127.0.0.1:6379> decr ticket    #ticket-1
QUEUED
127.0.0.1:6379> decrby lisi 100    #钱-100
QUEUED
127.0.0.1:6379>

在exec前票又被另一个人买走了

127.0.0.1:6379> decr ticket
(integer) 0
127.0.0.1:6379> get ticket
"0"
127.0.0.1:6379>

此时票数为0, lisi提交

127.0.0.1:6379> 
127.0.0.1:6379> exec    #失败
(nil)
127.0.0.1:6379> 
127.0.0.1:6379> get lisi    #钱并没有减少
"200"
127.0.0.1:6379>


最新手记推荐

• 用composer安装thinkphp框架的步骤 • 省市区接口说明 • 用thinkphp,后台新增栏目 • 管理员添加编辑删除 • 管理员添加编辑删除

全部回复(0)我要回复

暂无评论~
  • 取消 回复 发送
  • PHP中文网