Laravel 5记录编辑签入/签出功能(锁定)


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

我正在使用Laravel 5.1,并试图实现记录锁,当用户打开记录编辑视图,以便任何其他用户不能打开同一记录的编辑视图,直到锁被释放。

很明显,有时候用户永远不会完成编辑,所以我需要能够自动解锁记录(当用户进行任何其他事务时,或者在超时事件之后,或者使用ajax后台keep-alive调用)。

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

  1. 头痛。
  2. 我意识到它只在查询生成器中可用(我需要它for Eloquent)。
  3. 似乎这只是一个跨国锁定,而不是一个签入/签出记录锁定。

似乎有一个很大的混淆术语和mysql (innodb)锁实际做什么,或者它可能只是我试图弄清楚这个

长话短说,innodb/Laravel锁定(对于我的需求)的主要警告是,它不是持久的,因此它会在php脚本终止时重置自己,用户仍在编辑表单。它只用于事务。

我需要实现上述功能(编辑签入/签出),在我重新发明轮子之前,我想知道是否已经有一个内置的Laravel/PHP功能。

如果没有,我正在考虑以下方法,并希望得到关于哪一个是最好的输入。

。创建一个包含record_id, user_id,时间戳的edit_checkins

B。在记录表中添加一个locked_at列,它将保存一个时间戳或null(类似于deleted_at列)。

我主要关心的是性能&'垃圾收集',因为有时记录被锁定但从未主动解锁。使用方法A,我可以在一个简单的查询中从edit_checkins表中删除所有用户锁。然而,当检查记录是否被锁定时,它会慢一点,因为我将不得不做一个表连接(我认为它应该可以忽略不计,因为编辑事件比其他事件更少)。与方法B,它是更快的检查,但我没有得到所有的信息(如user_id),这是很难到几乎不可能实现解锁所有事件不知道user_id(我可能需要添加一个locked_by列以及记录)。

我希望我把问题讲清楚了。感谢您的宝贵时间。

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

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

你需要设计你自己的应用逻辑来做你想做的事情。我没有看到任何现有的Laravel包。有一种叫做larvel -record-lock,但是它不能做你想做的事情,而且它不会在多个请求之间持久化锁。

我认为最灵活的设计是创建一个record_locks表,然后创建一个多态关系与任何模型,你想是lockable。多态关系文档。让你开始:

DB表:

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 Model上调用方法,它会尝试在Eloquent Query Builder上调用该方法。如果它不存在,它将尝试在普通Query Builder上调用它。如果它不存在,你会得到一个错误。

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