问题描述
可以说我有一个查询,该查询使用其post
模型获得一个comment
模型。因此查询应该看起来像这样
Post::with(['comments'])->get();
现在,我想像这样实现laravel的悲观锁定
Post::with(['comments'])->sharedLock()->get();
它还会锁定评论表中的行吗?文档提到,
该文档提供了一个示例,该示例检索没有关系的1个模型实例。所以我不清楚天气是否适用于主要模型及其关系。
解决方法
因此,在进行了一些测试之后,似乎它确实也锁定了其关系行。这是我的情况。
我打开了2个标签,第一个标签打开了/locktest1
,另一个标签打开了/locktest2
。首先运行这样的功能
DB::transaction(function () {
dump(Post::with(['comments'])->sharedLock()->get());
sleep(5);
});
第二个带有/locktest2
的标签指向这样的功能
DB::transaction(function () {
dump(Comment::sharedLock()->get(),'done');
});
将sleep
放在模拟延迟的第一个函数之后。第二个函数中的第二个参数只是一个指示,让我看看第二个函数是否在第一个函数完成后立即运行。我用/locktest1
运行第一个选项卡,稍等片刻,然后用/locktest2
运行第二个选项卡。浏览器的两个加载指示器都在此时运行。 5秒后,第一个选项卡完成了其sleep
,第二个选项卡完成了之后的注释模型。
如果您使用共享锁,则在事务提交之前,行不会被修改。这不会阻止阅读。尝试更新以前锁定的资源后,该锁定就会生效。
另外,由于@Tim Lewis怀疑,默认情况下不会锁定渴望加载的关系。
我将给出两个示例路由,以测试不同的场景。只需在不同的浏览器标签中打开domain.com/test1和domain.com/test2。然后重新加载选项卡1,然后重新加载选项卡2。根据您取消注释的行,您会看到第二个选项卡的加载时间有所不同。
这在我的测试环境中适用于MariaDB版本10。
Route::get('test1',function () {
\DB::transaction(function () {
\App\User::with(['comments' => function ($query) {
// $query->sharedLock();
}])->sharedLock()->get();
sleep(15);
});
});
Route::get('test2',function () {
$user = \App\User::first();
$user->first_name = \Str::random(10);
// $user->save();
$comment = \App\Comment::sharedLock()->first();
$comment->created_at = \Carbon\Carbon::now()->addDays(array_rand(range(1,10000)));
// $comment->save();
});