- Redis的锁(一般用于分布式)(取钱这种场景都要加锁(watch))
1 悲观锁
很悲观,认为什么时候都会出问题,无论做什么(操作)都会加锁(这种情况会非常影响性能,无论干什么都会加锁,用完之后再去解锁)
2 乐观锁
很乐观,认为什么时候都不会出现问题,每次去拿数据的时候都会觉得不会进行修改,所以不会上锁,不过更新数据的时候会判断在此期间有没有进行数据的修改(是否有人修改这个数据 )
使用场景:秒杀业务
乐观锁在Redis中主要有两个操作步骤
1 获取version
2 更新的时候比较version
Redis的监视测试(监视:watch Redis加锁也是使用watch这个命令)
场景1(单线程操作),我有100元,另外一个人0元,我给另外一个人转20,我剩80,他有20
127.0.0.1:6379[2]> set money 100 #我有100 OK 127.0.0.1:6379[2]> set out 0 #他有0 OK 127.0.0.1:6379[2]> watch money #监视money对象(我的钱) OK 127.0.0.1:6379[2]> multi #开始事务 事务正常结束 数据期间没有发生变动 这个时候就正常执行成功 OK 127.0.0.1:6379[2]> decrby money 20 #我自建少20 QUEUED 127.0.0.1:6379[2]> incrby out 20 #他自增20 QUEUED 127.0.0.1:6379[2]> exec #执行事务 1) (integer) 80 #我有80 2) (integer) 20 #他有20
场景2(多线程操作),我有100元,另外一个人0元,我给另外一个人转20,这时候我工资到账我的钱发送改动watch会告诉事务我的钱发生变化,所有的事务都会操作失败
主线程转钱
127.0.0.1:6379[2]> set money 100 #我有100 OK 127.0.0.1:6379[2]> set out 0 #他有0 OK 127.0.0.1:6379[2]> watch money #监视对象 OK 127.0.0.1:6379[2]> multi #开启事务 OK 127.0.0.1:6379[2]> decrby money 20 #我的钱自减20,但是这时候副线程执行,我的钱发生变化 QUEUED 127.0.0.1:6379[2]> incrby out 20 #他的钱自增20 QUEUED 127.0.0.1:6379[2]> exec #执行事务 执行之前,副线程修改了值,这个时候就会导致事务执行失败 (nil) #执行失败,因为在转账后我的钱发生变化,事务执行失败
副线程工资到账(改变钱)
127.0.0.1:6379[2]> get money #查看当前的钱 "100" 127.0.0.1:6379[2]> set money 1000 #资金在转账过之后发生改动 OK
场景3(解锁 unwatch),放弃当前对象重新获取最新对象进行操作
如果修改失败,获取最新的值即可
步骤如下
1 如果发现事务执行失败,就先解锁
2 获取最新的值,再次监视
3 获取到最新的值之后再去执行事务
4 对监视的值有没有发生变化,如果没有变化,那么可以执行成功,如果发生变化就会执行失败,然后重新解锁再获取最新的锁
127.0.0.1:6379[2]> unwatch #解锁(放弃对象) 如果发现事务执行失败,就先解锁 OK 127.0.0.1:6379[2]> watch money #重新获取对象 获取最新的值,再次监视 OK 127.0.0.1:6379[2]> multi #开启事务 获取到最新的值之后再去执行事务 OK 127.0.0.1:6379[2]> decrby money 20 QUEUED 127.0.0.1:6379[2]> incrby out 20 QUEUED 127.0.0.1:6379[2]> exec #执行事务 比对监视的值有没有发生变化,如果没有变化,那么key执行成功,如果发生变化就会执行失败 1) (integer) 960 2) (integer) 30