如果突然有多个请求发送到我的数据库并同时更新,我想阻止我的数据库更新。
我创建一个用户Laravel Users Table作为示例,并使用JMeter模拟有两个用户,发送并发请求以更改同一行数据。
例如场景
我的银行帐户有$ 1000。同时,有两个请求从我的帐户向A和B先生转账。
我的余额记录为1000,请求1-向A先生发送$ 700,请求2-向B先生发送$ 700。如果我没有锁好桌子,系统将被视为我有足够的余额将钱寄出。
我的目标是当涉及到并发请求时,第二个(FIFO,即使是并发Web服务器仍然会对其进行处理,并将其中一个视为第二个)将引发异常/或显示返回错误要求说它正在使用中。
下面是我的测试代码,我使用JMeter运行测试。但是,测试显示两个请求都已更新。因此,最新请求将覆盖第一个请求。
以下,我希望Laravel会为数据库锁定抛出异常或错误,但仍会继续。
Route::get('/db-a', function() {
\DB::beginTransaction();
//lock the table
$rs = \DB::table('users')->where('id', '1')->lockForUpdate()->first();
$sql = "update users set remember_token='this is a' where id=1";
\DB::update(DB::raw($sql));
//purposely put the sleep to see can the table / row be locked
sleep(3);
\DB::commit();
$rs = DB::table('users')->where('id', '1')->first();
echo($rs->remember_token);
return;
});
Route::get('/db-b', function () {
\DB::beginTransaction();
//lock the table
$rs = \DB::table('users')->where('id', '1')->lockForUpdate()->first();
$sql = "update users set remember_token='this is b' where id=1";
\DB::update(DB::raw($sql));
//purposely put the sleep to see can the table / row be locked
sleep(3);
\DB::commit();
$rs = DB::table('users')->where('id', '1')->first();
echo($rs->remember_token);
return;
});
我做了另一个版本来手动捕获异常,但也无法正常工作
Route::get('db-callback-a', function() {
try {
app('db')->transaction(function () {
$record = \DB::table('users')->where('id', 1)->lockForUpdate()->first();
$sql = "update users set remember_token='this is callback a' where id=1";
\DB::update(DB::raw($sql));
sleep(3);
});
}
catch (\Exception $e) {
// display an error to user
echo('Database Row in Use, update later');
}
});
Route::get('db-callback-b', function () {
try {
app('db')->transaction(function () {
$record = \DB::table('users')->where('id', 1)->lockForUpdate()->first();
$sql = "update users set remember_token='this is callback b' where id=1";
\DB::update(DB::raw($sql));
sleep(3);
});
} catch (\Exception $e) {
// display an error to user
echo ('Database Row in Use, update later');
}
});