数据库字段 1. 错误的示范 2021 -06 -08 10 :57:59 * @return string */ function test1() { //商品id $id = request()-input( 'id' ); $product = Product::where( 'id' , $id )-firstOrFail(); if ( $product - num = 0 ) { return "卖光啦!
数据库字段
1. 错误的示范
2021-06-08 10:57:59* @return string
*/
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 模拟并发
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.redis 原子锁
2021-06-08 11:00:31*/
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();
}
}
库存正常
3.mysql 悲观锁
2021-06-08 11:00:47*/
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) {
}
}
库存正常
4.mysql 乐观锁
2021-06-08 11:00:47*/
function test4()
{
//商品id
$id = request()->input('id');
$product = Product::where('id', $id)->first();
if ($product->num <= 0) {
return "卖光啦!!";
}
//修改前检查库存和之前是否一致,不一致说明已经有变动,则放弃更改
$res = \DB::update('UPDATE `product`, [$id, $product->num]);
if (!$res) {
return '当前人数过多';
}
return 'success';
}
库存正常
优化乐观锁
修改库存的 sql 修改为
\DB::update('UPDATE `product`, [$id]);5.redis 存储库存
2021-06-15 15:18:31* @return string
*/
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';
}