我试图阻止无意重复请求,这是在双击按钮时第二次更改模型。我执行以下操作。
Log::debug('Begin transaction');
DB::beginTransaction();
$pdo = DB::connection()->getPdo();
$pdo->exec('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
try {
$user = \App\User::sharedLock()->find($id);
Log::debug('Select user: ' . pickfield($user));
if ($user->checkout) {
Log::debug('Already checked out, rollback');
DB::rollback();
return Redirect::back()->with('error', 'Already checked out');
}
Log::debug('Changing checkout..');
$user->checkout = new \DateTime($request->input('checkout'));
Log::debug('Saving checkout: ' . pickfield($user));
$user->save();
Log::debug('Commit!');
DB::commit();
} catch(\Exception $e) {
Log::debug('Error, rollback!');
DB::rollback();
}
事务仍然运行,因此彼此重叠,并且即使我放置了具有可序列化隔离的共享锁后,SELECT语句仍会检索不一致的模型。
[2019-05-17 01:02:45] local.DEBUG: Begin transaction
[2019-05-17 01:02:45] local.DEBUG: Begin transaction
[2019-05-17 01:02:45] local.DEBUG: Select user: {"id":3225,"checkout":null}
[2019-05-17 01:02:45] local.DEBUG: Changing checkout..
[2019-05-17 01:02:45] local.DEBUG: Saving checkout: {"id":3225,"checkout":{"date":"2019-05-17 01:02:45.428000","timezone_type":2,"timezone":"Z"}}
[2019-05-17 01:02:45] local.DEBUG: On model updating: {}
[2019-05-17 01:02:45] local.INFO: Sending email to user1@example.com
[2019-05-17 01:02:45] local.DEBUG: Begin transaction
[2019-05-17 01:02:45] local.DEBUG: Select user: {"id":3225,"checkout":null}
[2019-05-17 01:02:45] local.DEBUG: Changing checkout..
[2019-05-17 01:02:45] local.DEBUG: Saving checkout: {"id":3225,"checkout":{"date":"2019-05-17 01:02:45.604000","timezone_type":2,"timezone":"Z"}}
[2019-05-17 01:02:45] local.DEBUG: On model updating: {}
[2019-05-17 01:02:45] local.INFO: Sending email to user1@example.com
[2019-05-17 01:03:00] local.DEBUG: Commit!
[2019-05-17 01:03:00] local.DEBUG: Error, rollback!
尽管我的代码已经保证可以防止在另一笔交易中间执行SELECT
查询。我使用InnoDB。
相关,无解:Laravel pessimistic lock not working like supposed to
有什么解释或解决方案吗?
答案 0 :(得分:1)
一种可能的解决方案是在到达终点之前禁用该按钮,这很重要,即使您设法解决了此问题,因为您根本不应该(尽可能多地)发送重复的请求。
答案 1 :(得分:1)
哦!我很困惑。
这是我的锁定类型不正确。应该是lockForUpdate
。
“用于更新”锁可防止修改行或使用其他共享锁选择行。
共享锁,
共享锁可防止对选定的行进行修改,直到 您的交易提交。
我已经使用MyISAM引擎进行了测试,但根本无法正常工作,这就是为什么让我感到困惑。