您正在尝试做的是对记录的应用程序级锁定。您有一个业务级别要求,即一次只能有一个用户查看记录的编辑视图。这种“锁定”可以持续几秒钟、几分钟、几小时,或者你希望允许的任何最大超时。
这与记录上的数据库级锁完全不同。需要数据库级锁来确保两个更新语句不会同时在同一记录上运行。这个锁只会持续到事务需要的时间,通常只有几毫秒。长时间运行或开放式数据库事务不是一个好主意。
您将需要设计自己的应用程序逻辑来做您想做的事。我没有看到任何现有的 Laravel 包。有一个叫做laravel-record-lock,但它不会做你想做的事情,它不会在多个请求中保持锁。
我认为最灵活的设计是创建一个record_locks
表,然后与您想要的任何模型创建多态关系lockable
。多态关系文档。为了让你开始:
数据库表:
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 查询构建器回退到普通查询构建器。如果您在 Eloquent 模型上调用方法,它会尝试在 Eloquent 查询构建器上调用它。如果它在那里不存在,它会尝试在普通的查询生成器上调用它。如果那里不存在,你会得到一个错误。
所以,如果你这样做\App\User::lockForUpdate()
,方法调用最终会过滤到普通的查询构建器(因为它在 Eloquent 模型或 Eloquent 查询构建器上不存在)。