watch / unwatch
当多个客户端需要操作同一个key时,就涉及到锁的问题了,在redis中,提供一个可以监视所需要操作的key的方法:
watch key1 [key2 ...]
,这个方法表示监视某一个key,在事务开启前使用,如果在执行事务时,这个key发生了变化,事务将取消。unwatch
,对应的,这个就是取消监视,注意,这个命令不能用在事务中。
setnx(分布式锁)
对于watch来说,重点是修改key,一旦key被修改,事务就被取消,但是对于抢购来说,不可能别人买了东西,你就不能买了,正常来说,只要这个商品还有,就能够购买。
这个时候就需要用到分布式锁,分布式锁的原理其实也比较简单,用set命令就可以做到。分析抢购的场景我们可以知道,加锁应该是对一个商品来加锁,比如抢购可乐,我们可以定义一个锁:lock-cola,在购买前,我们先看看这个锁有没有其他人用,没人用那我就去买,如果有人在用了,那我就在后面排队。
怎么看这锁有没有人在用呢?setnx lock-cola 1
,如果我们设值失败的话,说明这个key已经存在,也就是说已经有人在我前面锁住了,如果我们设值成功,那就说明我们可以正常购买,同时给这个商品加了锁,在我买完之前,别人不能买,然后我们买完东西后在把key删了,后面的人就可以正常购买了。
但是关于这个setnx
,有2点需要注意:
- 关于锁的key的定义需要有统一的规范,如果对于同一个商品,每个人锁的不一样,那就没有意义。
- 为了防止一个客户端在上了锁后宕机,导致这个锁不能被释放,通常要给锁设置过期时间,这个过期时间具体是多少需要更具实际场景来定,如果我们使用
setnx
,那么设置过期时间必然需要第二条命令,这不能保证操作的原子性,所以推荐使用:set key value [ex seconds] [px milliseconds] nx
。