Я хочу запретить обновление моей базы данных, если внезапно несколько запросов отправляются в мою базу данных и обновляются одновременно.
Я создаю пользовательскую таблицу пользователей Laravel в качестве примера и использую JMeter для симуляции двух пользователей, отправляющих параллельный запрос на изменение одной и той же строки данных.
Например, сценарий
Мой банковский счет имеет 1000 долларов. В то же время два запроса на перевод денег г-ну А и г-ну Б. отправляются с моего счета.
Мой счет для баланса — 1000, Запрос 1 — Отправьте 700 долларов США г-ну А. и Запрос 2 — Отправьте 700 долларов США мистеру Б. Если я не заблокировал стол, система будет обработана, у меня достаточно средств для отправки денег.
Моя цель заключается в том, что когда речь идет о параллельном запросе, второй (FIFO, даже если это параллельный веб-сервер все еще будет обрабатывать его и обрабатывать один из них как второй) бросить исключение / или показать ошибку возврата На запрос сказано, что он используется.
ниже приведен мой код для теста, и я использую 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');
}
});
Задача ещё не решена.
Других решений пока нет …