Redis事务冲突问题
场景:你的 老婆和子女 同时拿你的淘宝去参加双十一抢购。老婆买了8k的包,儿子买了5k的电脑,女儿买了1k的化妆品。假设,你的账户只有10k。
此时,我们的事务对三次请求都进行判断,发现三个请求都小于10k,此时执行的话,显然是不正确的。如下:
怎么办呢?这里,我们就要引出我们的乐观锁和悲观锁了。
3.1 悲观锁
悲观锁:每次取数据的时候都认为别人会修改这个数据,所以每次取数据我们都将该数据上锁,如此,当别人也想取这个数据的时候,就会被阻塞,直到第一个人操作完成,解锁了,第二个人才能拿到锁,并操作这个数据。
他是怎么解决上面的问题的呢?
答:首先,第一个请求拿到10k的数据,并把10k上锁,第二、三个请求就没法访问那个数据了(被阻塞)。然后第一个请求判断8k < 10k,可以买,此时剩下2k,解开锁,第二个请求拿到锁了,锁上,把数据取出来,一看,诶!剩下2k了,糟糕,5k买不了呀,执行失败。解开锁。第三个请求拿到锁,取出数据,哈哈,还有2k,买个1k的东西绰绰有余,你的支付宝就剩下1k了。
3.2 乐观锁
乐观锁:每次取数据都认为别人不会修改,不上锁,但是在更新数据的时候会通过取数据时候的版本号和此时数据库中该数据的版本号进行比较,如果版本号不同则不执行更新操作。这种做法可以提高吞吐量,适用于多读的应用类型。
他是怎么解决上面的问题的呢?
答:首先,第一个请求和第二个请求拿到10k的数据的时候,该数据的版本号是1.0。此时:
我们第一个请求先判断成功,减去8k后,发现数据库中该数据的版本号与自己一致,将数据2k写入数据库,并将版本号更改为1.1。
第二个请求也判断成功了,减去2k后,发现数据库的版本号跟自己不一致,减5k的操作不执行。再次获取新的数据,发现此时2k 小于 5k,操作失败。
第三个请求获取数据为2k和版本号为1.1,减去1k后,检查到数据库中该数据的版本号和自己一样,将数据1k写入数据库,并将版本号改为1.2。