乐观锁和悲观锁看名称挺高大上的, 面试的时候一些面试官最喜欢拿这个来考应聘者. 这个也是有意义的, 一个 PHP 程序员如果没有接触过乐观锁和非观锁, 那么他根本没有接触过像样的业务了.
什么是悲观锁? 看意思就是比较, 不相信其它的人不会改, 所以查询的时候就加锁, 然后自己更新数据再释放锁. 可以有效防止减库存冲突问题.
什么是乐观锁? 相反就是认为没几个人用, 基本不会碰到有人修改, 所以查询时就不加锁, 然后更新的时候判断一下数据是不是被改掉.
在 php+mysql 程序中怎么实现呢? 代码也很简单.
悲观锁的业务流程 (以商品表和 SKU 表减库存并进行其它操作为类):
--- 事务开始
1, 查询商品表, 锁定表: for update
2, 判断商品库存是否大于购买数据,
3, 如果库存满足, 减少商品表库存.(不满足就回滚事务了.)
4, 减少商品 SKU 表库存
5, 记录订单操作记录等
-- 事务提交 (事务提交时即释放锁).
可见上面的流程中整个被锁的周期是比较长的. 如果改为乐观锁呢:
---- 事务开始
1, 查询商品表
2, 判断商品库存是否大于购买数据,
3, 如果库存满足, 减少商品表库存 (条件是商品表的库存 = 1 中查询出的库存)
比如: update product set store = store - {$count} where store = {$product->store} ($product->store 为 1 查询得到的库存)
4, 减少商品 SKU 表库存 (同样需要判断条件)
5, 记录订单操作记录等
-- 事务提交 (事务提交时即释放锁).
可以看到乐观锁整个过程中实际并未执行任何加锁, 我也不知道为什么会有这样的称呼. 实际它是一种判断冲突的有效手段.
在上面的乐观锁的执行流程中, 如果 3,4,5 这三步中的任何一步发生异常, 都会因滚事务. 这样就不会出现减库存冲突导致库存脏数据了.
在使用乐观锁时, 要考虑进一步, 就是在乐观锁时如果发现数据被修改, 更新失败时, 要考虑再重新获取数据, 重新判断重新更新. 这样就不会因为更新失败导致此笔业务失败, 而相当于把它立即加进到下一步的队列而在同步请求中即能得到解决.
两种锁各有各的好, 建议电商网站起步时访问量不大, 不会造成压力时使用悲观锁. 因为这时没有什么高并发, 但也要好好检查代码防止出现死锁.
对于成熟的电商网站, 必须面对高并发的情况下, 应该使用乐观锁.
来源: http://www.qdfuns.com/article/45387/da67b534557bee719eaa948fc28ab9e1.html