【问题标题】:Does Laravel's pessimistic lock effects its relationship model as well?Laravel 的悲观锁是否也会影响其关系模型?
【发布时间】:2020-09-02 17:04:39
【问题描述】:

假设我有一个查询,它获取一个带有 comment 模型的 post 模型。所以查询应该是这样的

Post::with(['comments'])->get();

现在,我想像这样实现 laravel 的悲观锁定

Post::with(['comments'])->sharedLock()->get();

它是否也会锁定评论表中的行?文档中提到,

共享锁可防止选定的行在事务提交之前被修改

文档提供了一个检索 1 个没有关系的模型实例的示例。所以我不清楚它是否适用于主要模型及其关系。

【问题讨论】:

  • 我的直觉说可能不是,但我不确定。你也许可以做Post::with(['comments' => function($query){ $query->sharedLock(); })->sharedLock()->get();,但我不能说我曾经以这种方式使用过悲观锁定。
  • 有趣的拍摄! @蒂姆刘易斯
  • @TimLewis 可以证实您的假设。我刚刚在一个新的应用程序上对其进行了测试。

标签: laravel query-builder pessimistic-locking


【解决方案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,第二个选项卡在此之后立即完成获取评论模型。

【讨论】:

  • 我无法确认这种行为。我已经用一个新的 Laravel Applacation 测试了这个。而且在您的示例中,/locktest2 中也不应该有任何延迟,因为共享锁不会阻止读取,并且在您的示例中您不执行任何更新操作。
  • 感谢您指出,这是我的疏忽@shock_gone_wild
【解决方案2】:

如果您使用共享锁,则在事务提交之前,行会受到保护,不会被修改。这并不妨碍阅读。一旦尝试更新先前锁定的资源,锁定就会生效。

此外,正如@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();
});

【讨论】:

  • 假设事务关闭中有 2 个查询。第一个查询获取一个包含其所有关系的模型,而第二个查询从前一个查询更新其中一个行的关系。由于它们都在同一个事务关闭中,它会更新吗?还是会被锁定?
  • 在我试过你的例子之后,我的环境似乎有问题。据我了解,如果我在 2 个单独的选项卡上运行 /test1 然后 /test2 ,那么 test2 将不得不等待 /test1 完成。但据我观察,无论任何查询上的 sharedLock 是否被注释,/test2 仍将等待 /test1。我还在 phpmyadmin 上使用 MariaDB v.10。有什么想法吗?
  • 嗯.. 我正在将 MariaDB v10 与 InnoDB 引擎一起使用。你是否也考虑过 ->sharedLock()->get();选择用户时? $user->save() 那就得等了……
  • 我的设置也是一样的。我仔细检查了一下,我很确定我考虑过这种可能性。问题不在于它不等待交易完成。问题是无论是否存在 sharedLock() ,它都会等待事务完成。例如,如果我在 /test1 上评论 sharedLock()(同时保持 sleep()),/test2 仍将等待 sleep() 完成以使其最终更新,即使 /test1 没有强制执行 sharedLock( )。我在这里错过了什么吗?
猜你喜欢
  • 2016-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-16
  • 2010-09-12
  • 1970-01-01
  • 2014-08-30
相关资源
最近更新 更多