这里我们来学习watch监控命令,用watch来实现redis的乐观锁。
我们先来复习一下mysql中乐观锁和悲观锁的定义:
悲观锁:
很悲观,认为什么时候都会出问题,无论做什么都会加锁!
乐观锁:
1) 很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据,
2) 获取version
3) 更新的时候比较version,version发生改变则提交失败
在MySQL中乐观锁是使用version来实现,在redis中,乐观锁使用watch来实现。
下面我们使用一个例子来模拟一下乐观锁的操作:
1:正常消费操作
127.0.0.1:6379> set money 100 # 设置money 100
OK
127.0.0.1:6379> set out 0 # 设置 out 消费0
OK
127.0.0.1:6379> watch money # 开启监控
OK
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> INCrBY out 10 # 消费 + 10
QUEUED
127.0.0.1:6379(TX)> decrby money 10 # money -10
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务,发现成功。
1) (integer) 10
2) (integer) 90
127.0.0.1:6379> # 事务结束之后,watch自动失效
我们上边这是一个完整的乐观锁操作过程。但是在实际应用中,可能会出现并发,也就是说,在你事务执行过程中money就被其他人改变了,我们下边使用两个窗口来模拟一下并发操作。
2:并发消费操作
(1):窗口1:
127.0.0.1:6379> watch money # 监控money
OK
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> decrby money 10 # 消费10
QUEUED
127.0.0.1:6379(TX)> incrby money 10 # 消费金额新增10元
QUEUED
127.0.0.1:6379(TX)> # 这里我们不执行事务,模拟并发进入窗口2
(2):窗口2:
127.0.0.1:6379> watch money # 监控money
OK
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> set money 200 # 改变money
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务
1) OK
127.0.0.1:6379> # 监控失效
(3):再次回到窗口1
执行事务我们会发现,执行失败
127.0.0.1:6379> watch money # 监控money
OK
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> decrby money 10 # 改变money
QUEUED
127.0.0.1:6379(TX)> incrby money 10 # 改变out
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务失败,因为在执行事务之前,money已经被修改了。
(nil)
127.0.0.1:6379> # 注意:此时watch监控还未失效
(4):重试:在窗口1中
正常在我们程序逻辑中,用watch监控的事务执行失败之后会再次执行。
注意,watch监控的事务实行失败之后,watch还未失效,想要获取新的watch监控,需要先解除watch
127.0.0.1:6379> unwatch # 先解除watch
OK
127.0.0.1:6379> watch money # 监控money
OK
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> get money # 获取money
QUEUED
127.0.0.1:6379(TX)> decrby money 10 # 消费10
QUEUED
127.0.0.1:6379(TX)> incrby out 10 # 消费金额增加10
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务
1) "200"
2) (integer) 190
3) (integer) 20
127.0.0.1:6379>
经典面试题:redis如何实现乐观锁?
使用watch
以上大概就是redis乐观锁的基本实现。
有好的建议,请在下方输入你的评论。