简单理解MySQL乐观锁和悲观锁
乐观锁
乐观锁,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
乐观锁适用于 读多写少 的应用场景,可以提高吞吐量。
乐观锁:假设数据不会发生变化,只在提交操作时检查是否违反数据完整性。
悲观锁
悲观锁,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
实现
参照商城卖东西的过程
/** * 更新库存(不考虑并发) * @param productId * @return */ public function updateStockRaw(int $productId){ $product = query("SELECT * FROM product_stock WHERE product_id=?", $productId); if ($product['quantity'] > 0) { $updateCnt = update("UPDATE product_stock SET quantity=quantity-1 WHERE product_id=?", $productId); if($updateCnt > 0){ return true; //更新库存成功 } } return false; }
这段代码在默认情况下是正常运行的,但是秒杀等多用户同时并发情况下,会存在超卖的可能
悲观锁实现
public function updateStockRaw(int $productId){ $product = query("SELECT * FROM product_stock WHERE product_id=? FOR UPDATE", productId); if ($product['quantity'] > 0) { $updateCnt = update("UPDATE product_stock SET quantity=quantity-1 WHERE product_id=?", $productId); if($updateCnt > 0){ return true; //更新库存成功 } } return false; }
乐观锁实现
public function updateStockRaw(int $productId){ $updateCnt = 0; while ($updateCnt == 0) { $product = query("SELECT * FROM product_stock WHERE product_id=?", productId); if ($product['quantity'] > 0) { $updateCnt = update("UPDATE product_stock SET quantity=quantity-1 WHERE product_id=? AND quantity=?", $productId, $product['quantity']); if($updateCnt > 0){ return true; //更新库存成功 } }else{ return false; } } return false; }
使用乐观锁更新库存的时候不加锁,当提交更新时需要判断数据是否已经被修改(AND quantity=?),只有在 quantity等于上一次查询到的quantity时 才提交更新。