Laravel 5 记录编辑 check-in/check-out 功能(锁定)

Laravel 5 record editing check-in/check-out functionality (locking)

我正在使用 Laravel 5.1 并尝试在用户打开记​​录编辑视图时实施记录锁定,以便任何其他用户在释放锁定之前无法打开同一记录的编辑视图.

显然有时用户永远不会完成编辑,所以我需要能够自动解锁记录(当用户进行任何其他交易时,或在超时事件后,或 ajax后台保活调用)。

我研究了 lockForUpdate() 并阅读了有关 InnoDB 锁定功能的信息,但我无法获得有关它的真实信息(搜索了 20 多个帖子,他们似乎都在互相背诵而没有真实信息) .文档也没有提供太多信息,探索 Laravel 查询 Class 代码让我取得了以下进展:

  1. 头痛。
  2. 我意识到它只能在查询生成器中使用(Eloquent 我需要它)。
  3. 好像只是跨国锁定,不是checkin/checkout记录锁定。

似乎对术语和 mysql (innodb) 锁定的实际作用存在很大的混淆,或者可能只是我想弄清楚。

长话短说,InnodDB/Laravel 锁定(满足我的需要)的主要警告是它不是持久性的,因此当 php 脚本终止并且用户仍在编辑时它将自行重置表格。仅用于交易。

我需要实现上述功能(编辑 check-in/check-out),在我重新发明轮子之前,我很想知道是否已经有内置的 Laravel/PHP 功能。

如果没有,我正在考虑以下方法,并希望获得关于哪种方法最好的意见。

一个。使用 record_id、user_id、时间戳创建 edit_checkins table。

乙。将 locked_at 列添加到记录 table 中,它将包含时间戳或空值(类似于 deleted_at 列)。

我主要关心的是性能 & 'garbage collection' 因为有时记录被锁定但从未主动解锁。使用方法 A,我可以在一个简单的查询中从 edit_checkins table 中删除所有用户锁。然而,当检查记录是否被锁定时它会有点慢,因为我将不得不做一个 table 连接(我认为它应该可以忽略不计,因为编辑事件比其他事件少)。使用方法 B,检查速度更快,但我没有获得所有信息(例如 user_id),并且在不知道 user_id 的情况下实施解锁所有事件几乎不可能](我可能还需要在记录中添加一个 locked_by 列)。

我希望我把问题说清楚了。谢谢你的时间。

您尝试做的是对记录的应用程序级锁定。您有一个业务级别要求,即一次只能有一个用户查看记录的编辑视图。此 "lock" 可以持续几秒、几分钟、几小时或您希望允许的任何最大超时。

这与记录上的数据库级锁完全不同。需要数据库级锁以确保两个更新语句不会同时 运行 在同一记录上。这个锁只会持续到事务需要的时间,通常只有几毫秒。长 运行ning 或开放式数据库事务不是一个好主意。

您将需要设计自己的应用程序逻辑来执行您想要的操作。我没有看到任何现有的 Laravel 软件包。有一个名为 laravel-record-lock,但它不会执行您想要执行的操作,并且不会在多个请求中保持锁定。

我认为最灵活的设计是创建一个 record_locks table,然后创建与您希望成为的任何模型的多态关系 lockablePolymorphic relationship documentation。入门指南:

DB table:

record_locks
    - id
    - timestamps (if you want)
    - lockable_id - integer
    - lockable_type - string
    - user_id - integer
    - locked_at - datetime/timestamp

型号

class RecordLock extends Model
{
    /**
     * Polymorphic relationship. Name of the relationship should be
     * the same as the prefix for the *_id/*_type fields.
     */
    public function lockable()
    {
        return $this->morphTo();
    }

    /**
     * Relationship to user.
     */
    public function user()
    {
        return $this->belongsTo('App\User');
    }

    // additional functionality
}

现在您可以将多态关系添加到您想要锁定的任何模型:

class Book extends Model
{
    /**
     * Polymorphic relationship. Second parameter to morphOne/morphMany
     * should be the same as the prefix for the *_id/*_type fields.
     */
    public function recordLock()
    {
        return $this->morphOne('App\RecordLock', 'lockable');
    }
}

class Car extends Model
{
    /**
     * Polymorphic relationship. Second parameter to morphOne/morphMany
     * should be the same as the prefix for the *_id/*_type fields.
     */
    public function recordLock()
    {
        return $this->morphOne('App\RecordLock', 'lockable');
    }
}

最后,作为常规关系使用:

$book = \App\Book::first();
$lock = $book->recordLock; // RecordLock object or null

$car = \App\Car::first();
$lock = $car->recordLock; // RecordLock object or null

/**
 * Accessing the relationship from the RecordLock object will
 * dynamically return the type of object that was locked.
 */

$lock = \App\RecordLock::find(1);
$lockedObject = $lock->lockable; // \App\Book object

$lock = \App\RecordLock::find(2);
$lockedObject = $lock->lockable; // \App\Car object

最后一个旁注来解决您对查询生成器与 Eloquent 的担忧:Eloquent 模型回退到 Eloquent 查询生成器,而 Eloquent 查询Builder 退回到普通的 Query Builder。如果您在 Eloquent 模型上调用方法,它会尝试在 Eloquent 查询生成器上调用它。如果它在那里不存在,它会尝试在普通查询生成器上调用它。如果它不存在,你会得到一个错误。

因此,如果您要执行 \App\User::lockForUpdate(),方法调用最终会过滤到普通查询生成器(因为它不存在于 Eloquent 模型或 Eloquent查询生成器)。