laravel解决超卖的几个方法
数据库字段

1 错误的示范
function test1(){$id = request()->input('id');$product = Product::where('id', $id)->firstOrFail();if ($product->num <= 0) return "卖光啦!!";$product->decrement('num'); //库存减1return "success";}
使用 go 模拟并发
package mainimport ("fmt""github.com/PeterYangs/tools/http""sync")func main() {client := http.Client()wait := sync.WaitGroup{}for i := 0; i < 50; i++ {wait.Add(1)go func(w *sync.WaitGroup) {defer w.Done()res, _ := client.Request().GetToString("http://www.api/test1?id=1")fmt.Println(res)}(&wait)}wait.Wait()}

2 方案1 redis 原子锁
function test2(){$id = request()->input('id');$lock = \Cache::lock("product_" . $id, 10);try {//最多等待5秒,5秒后未获取到锁,则抛出异常$lock->block(5);$product = Product::where('id', $id)->firstOrFail();if ($product->num <= 0) {return "卖光啦!!";}$product->decrement('num');return 'success';}catch (LockTimeoutException $e) {return '当前人数过多';} finally {optional($lock)->release();}}

3 方案2 mysql 悲观锁
function test3(){$id = request()->input('id');try {\DB::beginTransaction();$product = Product::where('id', $id)->lockForUpdate()->first();if ($product->num <= 0) {return "卖光啦!!";}$product->decrement('num');\DB::commit();return "success";} catch (\Exception $exception) {}}
库存正常
4 方案3 mysql 乐观锁
function test4(){$id = request()->input('id');$product = Product::where('id', $id)->first();if ($product->num <= 0) {return "卖光啦!!";}//修改前检查库存和之前是否一致,不一致说明已经有变动,则放弃更改$res = \DB::update('UPDATE `product` SET num = num -1 WHERE id = ? AND num=?', [$id, $product->num]);if (!$res) {return '当前人数过多';}return 'success';}
库存正常优化乐观锁修改库存的 sql 修改为\DB::update(‘UPDATE product SET num = num -1 WHERE id = ? AND num-1 >= 0’, [$id]);
5 方案4 redis 存储库存
function test5(){$id = request()->input('id');$num = Redis::command('get', ['product_' . $id]);if ($num <= 0) {return "卖完啦!";}$re = Redis::command('decrby', ['product_' . $id, 1]);//减多了回滚if ($re < 0) {Redis::command('incrby', ['product_' . $id, 1]);return "卖完啦!";}return 'success';}
库存正常原文链接:https://blog.csdn.net/weixin_41882200/article/details/119249367欢迎补充