首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >电商库存超卖常见方案总结

电商库存超卖常见方案总结

作者头像
兔云小新LM
发布2021-07-15 15:36:44
发布2021-07-15 15:36:44
95600
代码可运行
举报
运行总次数:0
代码可运行

字段设计

错误示例

代码语言:javascript
代码运行次数:0
运行
复制
function test1()
{

    //商品id
    $id = request()->input('id');

    $product = Product::where('id', $id)->firstOrFail();

    if ($product->num <= 0) {

        return "卖光啦!!";
    }

    //库存减1
    $product->decrement('num');

    return "success";

}

使用go模拟并发

代码语言:javascript
代码运行次数:0
运行
复制
package main

import (
    "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()

}

在数据库中查看库存

redis原子锁

代码语言:javascript
代码运行次数:0
运行
复制
function test2()
{
    //商品id
    $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 "卖光啦!!";
        }
        //库存减1
        $product->decrement('num');

        return 'success';

    }catch (LockTimeoutException $e) {

        return '当前人数过多';

    } finally {

        optional($lock)->release();
    }
}

MySQL悲观锁

代码语言:javascript
代码运行次数:0
运行
复制
function test3()
{

    //商品id
    $id = request()->input('id');

    try {
        \DB::beginTransaction();
        $product = Product::where('id', $id)->lockForUpdate()->first();

        if ($product->num <= 0) {

            return "卖光啦!!";
        }

        //库存减1
        $product->decrement('num');

        \DB::commit();

        return "success";

    } catch (\Exception $exception) {

    }

}

MySQL乐观锁

代码语言:javascript
代码运行次数:0
运行
复制
function test4()
{

  //商品id
  $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';


}

优化

代码语言:javascript
代码运行次数:0
运行
复制
\DB::update('UPDATE `product` SET num = num -1 WHERE id = ? AND num-1 >= 0', [$id]);

适用Redis存储库存

代码语言:javascript
代码运行次数:0
运行
复制
function test5()
{

    //商品id
    $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';
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 卡二条的技术圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 字段设计
  • 错误示例
  • redis原子锁
  • MySQL悲观锁
  • MySQL乐观锁
  • 适用Redis存储库存
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档