ASCII码 ASCII码

laravel解决超卖的几个方法

发布于:2022-06-23 12:43:51  栏目:技术文档

数据库字段

1 错误的示范

  1. function test1()
  2. {
  3. $id = request()->input('id');
  4. $product = Product::where('id', $id)->firstOrFail();
  5. if ($product->num <= 0) return "卖光啦!!";
  6. $product->decrement('num'); //库存减1
  7. return "success";
  8. }
使用 go 模拟并发
  1. package main
  2. import (
  3. "fmt"
  4. "github.com/PeterYangs/tools/http"
  5. "sync"
  6. )
  7. func main() {
  8. client := http.Client()
  9. wait := sync.WaitGroup{}
  10. for i := 0; i < 50; i++ {
  11. wait.Add(1)
  12. go func(w *sync.WaitGroup) {
  13. defer w.Done()
  14. res, _ := client.Request().GetToString("http://www.api/test1?id=1")
  15. fmt.Println(res)
  16. }(&wait)
  17. }
  18. wait.Wait()
  19. }

2 方案1 redis 原子锁

  1. function test2()
  2. {
  3. $id = request()->input('id');
  4. $lock = \Cache::lock("product_" . $id, 10);
  5. try {
  6. //最多等待5秒,5秒后未获取到锁,则抛出异常
  7. $lock->block(5);
  8. $product = Product::where('id', $id)->firstOrFail();
  9. if ($product->num <= 0) {
  10. return "卖光啦!!";
  11. }
  12. $product->decrement('num');
  13. return 'success';
  14. }catch (LockTimeoutException $e) {
  15. return '当前人数过多';
  16. } finally {
  17. optional($lock)->release();
  18. }
  19. }

3 方案2 mysql 悲观锁

  1. function test3()
  2. {
  3. $id = request()->input('id');
  4. try {
  5. \DB::beginTransaction();
  6. $product = Product::where('id', $id)->lockForUpdate()->first();
  7. if ($product->num <= 0) {
  8. return "卖光啦!!";
  9. }
  10. $product->decrement('num');
  11. \DB::commit();
  12. return "success";
  13. } catch (\Exception $exception) {
  14. }
  15. }

库存正常

4 方案3 mysql 乐观锁

  1. function test4()
  2. {
  3. $id = request()->input('id');
  4. $product = Product::where('id', $id)->first();
  5. if ($product->num <= 0) {
  6. return "卖光啦!!";
  7. }
  8. //修改前检查库存和之前是否一致,不一致说明已经有变动,则放弃更改
  9. $res = \DB::update('UPDATE `product` SET num = num -1 WHERE id = ? AND num=?', [$id, $product->num]);
  10. if (!$res) {
  11. return '当前人数过多';
  12. }
  13. return 'success';
  14. }

库存正常优化乐观锁修改库存的 sql 修改为\DB::update(‘UPDATE product SET num = num -1 WHERE id = ? AND num-1 >= 0’, [$id]);

5 方案4 redis 存储库存

  1. function test5()
  2. {
  3. $id = request()->input('id');
  4. $num = Redis::command('get', ['product_' . $id]);
  5. if ($num <= 0) {
  6. return "卖完啦!";
  7. }
  8. $re = Redis::command('decrby', ['product_' . $id, 1]);
  9. //减多了回滚
  10. if ($re < 0) {
  11. Redis::command('incrby', ['product_' . $id, 1]);
  12. return "卖完啦!";
  13. }
  14. return 'success';
  15. }

库存正常原文链接:https://blog.csdn.net/weixin_41882200/article/details/119249367欢迎补充

相关推荐
阅读 +