網站訪問量達到一定規模的時候,併發使用者都在改資料的時候,可能會出現問題,比如一個活動限制10個人參與,一個簡單的方式是在資料中設定一個欄位為 0,一個使用者參與了就 +1 ,但是當多個使用者同時參與活動的時候,有可能會多於10個使用者參與了活動,這樣的問題是由於資料庫沒有設定悲觀鎖導致的,但是如何在本地開發環境復現這種併發呢?
使用 guzzlehttp/guzzle
包,可以在本地模擬併發請求
use GuzzleHttp\Client;
// 併發請求程式碼
$client = new Client(['base_uri' => 'http://test.com/']);
$promises = [
'a' => $client->getAsync('bonus.php?money=13'),
'b' => $client->getAsync('bonus.php?money=23'),
'c' => $client->getAsync('bonus.php?money=33'),
'd' => $client->getAsync('bonus.php?money=43')
];
$results = Promise\unwrap($promises);
echo $results['a']->getBody()->getContents();
echo "\n";
echo $results['b']->getBody()->getContents();
echo "\n";
echo $results['c']->getBody()->getContents();
echo "\n";
echo $results['d']->getBody()->getContents();
echo "\n";
我們在 bonus.php
這個路由中,可以嘗試對資料庫修改
$rand = request()->get('money',0);
DB::beginTransaction();
try{
$old_money = DB::table('test_table')->where('user_id','34')->lockForUpdate()->value('total_money');
DB::table('test_table')->where('user_id','34')->update(['total_money'=>$rand]);
$new_money = DB::table('test_table')->where('user_id','34')->value('total_money');
DB::commit();
$data = ['old_money'=>$old_money,'new_money'=>$new_money];
}catch (\Exception $e){
$data = ['info'=>'rollback'];
DB::rollBack();
}
dd($data);
可能的輸出結果是,money 由 23 變成 13,然後由 13 變成了 33,然後由 33 變成了43 ,如果不使用悲觀鎖,則資料庫記錄就會出現問題
本作品採用《CC 協議》,轉載必須註明作者和本文連結