1.为什么要有悲观锁、乐观锁?
商品购买过程一般如下图所示:
用户买东西的时候,数据库通常会先查一下库存,有足够的库存后用户可以继续购买,用户确认订单后就修改库存。
假设有这么一个场合。一个秒杀活动放出了3台macbook,1元一台。
用户甲手快买了2件。按照步骤来是,数据库查询有没有足够的库存,查了一下,有3个库存。然后数据库还没来得及修改库存的时候,用户乙也买了2台,数据库查询库存,也有3件。结果用户甲和用户乙都成功下单了。3件库存结果卖了4件出去。悲观锁和乐观锁就是为了解决这种问题而出现的。
2.悲观锁
悲观锁就是总是假设最坏的情况,即假设每次都会出现上面的那种情况。悲观锁的解决方案就是当数据库查询库存时,即让数据库对该记录加锁,直到修改完库存后再解锁。在记录被加锁之后,只有当记录被解锁后,其他用户才能进行库存查询。
select stock from tb_sku where id=1 for update; # sql原生语句用法 SKU.objects.select_for_update().get(id=1) # django ORM用法
悲观锁类似于在多线程资源竞争时添加的互斥锁,容易出现死锁现象,采用不多。
3.乐观锁
乐观锁就是总是假设最好的情况,即假设每次都不会出现上面的那种情况。乐观锁其实并没有加锁,只是在更新数据时,判断数据在查询出来之后是否有被别人修改过,如果没有修改才更新,否则不更新(更新商品库存时,先判断库存是否与之前查询的一样,如果一样则更新,否则不更新)。
update tb_sku set stock=1 where id=1 and stock=3; # sql原生语句写法
SKU.objects.filter(id=1, stock=3).update(stock=1) # django ORM写法
注意:乐观锁并不存在真正的锁,只是在修改数据时作了数据是否有被修改的判断
特别注意:如果使用乐观锁,记得要修改数据库的隔离级别为读已提交(Read Committed)