dev*_*ev7 1 php mysql record-locking laravel
我正在使用Laravel 5.1并尝试在用户打开记录编辑视图时实现记录锁定,以便任何其他用户无法打开同一记录的编辑视图,直到锁定被释放.
很明显,用户永远不会完成编辑,因此我需要能够自动解锁记录(当用户进行任何其他事务时,或者在超时事件之后,或者使用ajax后台保持活动状态).
我已经查看了lockForUpdate()有关InnoDB锁定功能的内容,但我无法获得有关它的真实信息(搜索超过20个帖子,他们似乎都没有真正的信息相互背诵).文档也没有提供太多信息,探索Laravel Query Class代码让我获得了以下进展:
看起来术语和mysql(innodb)锁定实际上存在很大的混淆,或者它可能只是我试图解决这个问题.
长话短说,InnodDB/Laravel锁定的主要警告(根据我的需要)是它不持久,因此当php脚本终止并且用户仍在编辑表单时它将自动重置.它仅适用于交易.
我需要实现上述功能(编辑签入/签出),在我重新发明轮子之前,我很想知道是否已经内置了Laravel/PHP功能.
如果没有,我正在考虑以下方法,并希望得到关于哪一个是最好的输入.
A. edit_checkins使用record_id,user_id,timestamp 创建一个表.
B. locked_at在记录表中添加一个列,该列将保存时间戳或null(类似于deleted_at列).
我主要担心的是性能和"垃圾收集",因为有时候记录被锁定但从未主动解锁.使用方法AI可以edit_checkins在简单查询中从表中删除所有用户锁.但是在检查记录是否被锁定时会慢一点,因为我必须进行表连接(我认为它应该可以忽略不计,因为编辑事件比其他事件更少).使用方法B检查更快但我没有获得所有信息(例如user_id)并且在不知道user_id的情况下实现解锁所有事件更难以几乎不可能(我可能需要locked_by同时在记录中添加一列).
我希望我的问题足够清楚.感谢您的时间.
您要做的是对记录执行应用程序级锁定.您有一个业务级别要求,一次只有一个用户可以查看记录的编辑视图.此"锁定"可以持续数秒,分钟,小时或您希望允许的最大超时.
这与记录上的数据库级别锁定完全不同.需要数据库级别锁定以确保两个更新语句不会同时在同一记录上运行.只有事务处理时,此锁定才会持续,通常只需几毫秒.长时间运行或开放式数据库事务不是一个好主意.
您将需要设计自己的应用程序逻辑来执行您想要的操作.我没有看到任何现有的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
Run Code Online (Sandbox Code Playgroud)
模型
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
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以将多态关系添加到要锁定的任何模型:
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');
}
}
Run Code Online (Sandbox Code Playgroud)
最后,使用常规关系:
$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
Run Code Online (Sandbox Code Playgroud)
最后一个旁注来解决您对Query Builder与Eloquent的关注:Eloquent Model回退到Eloquent Query Builder,而Eloquent Query Builder则回归到简单的Query Builder.如果在Eloquent Model上调用方法,它会尝试在Eloquent Query Builder上调用它.如果它不存在,它会尝试在纯查询生成器上调用它.如果那里不存在,你会收到错误.
因此,如果您这样做\App\User::lockForUpdate(),方法调用最终会过滤到简单的查询生成器(因为它不存在于Eloquent模型或Eloquent Query Builder中).
| 归档时间: |
|
| 查看次数: |
2694 次 |
| 最近记录: |