简体   繁体   English

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

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

I am using Laravel 5.1 and trying to implement a record lock when a user is opening a record edit view so that any other user can't open the edit view for the same record until the lock is released. 我正在使用Laravel 5.1并尝试在用户打开记​​录编辑视图时实现记录锁定,以便其他任何用户在释放锁定之前都无法打开同一记录的编辑视图。

There are obviously times that a user will never finish the editing so I need to be able to automatically unlock the record (either when the users makes any another transactions, or after a timeout event, or with an ajax background keep-alive call). 显然,有时候用户永远都不会完成编辑,因此我需要能够自动解锁记录(当用户进行任何其他事务时,或者在发生超时事件之后,或者通过ajax后台保持活动调用)。

I've looked into the lockForUpdate() and read about InnoDB locking feature but I couldn't get real info about it (searched over 20 posts and they all seem to recite each other with no real information). 我研究了lockForUpdate()并阅读了有关InnoDB锁定功能的信息,但我无法获得有关它的真实信息(搜索了20多个帖子,他们似乎彼此背诵,没有真实信息)。 The Docs also don't offer too much info and exploring the Laravel Query Class code got me the following progress: Docs也没有提供太多信息,而探索Laravel查询类代码为我带来了以下进步:

  1. Headache. 头痛。
  2. I realized that it is only available in the Query Builder (I need it for Eloquent). 我意识到它仅在查询生成器中可用(我需要Eloquent使用)。
  3. Seems like it is only a transnational locking not a checkin/checkout record locking. 似乎只是跨国锁定,而不是签入/签出记录锁定。

It seems like there's a big confusion both with terminology and with what mysql (innodb) locking actually does, or it could be just me trying to figure this out. 似乎术语和mysql(innodb)锁定的实际作用都造成了很大的混淆,或者可能只是我试图弄清楚这一点。

Long story short, the main caveat with InnodDB/Laravel locking (for my needs) is that it is not persistent hence it will reset itself when the php script terminates and the user is still editing the form. 长话短说,使用InnodDB / Laravel锁定(主要是为了满足我的需要)的主要警告是它不是持久性的,因此它将在php脚本终止并且用户仍在编辑表单时重置自身。 It is only for transactions. 仅用于交易。

I need to achieve the mentioned functionality (editing check-in/check-out) and before I re-invent the wheel I would love to know if there's already a built-in Laravel/PHP functionality for it. 我需要实现上述功能(编辑签入/签出),在重新发明轮子之前,我想知道是否已经有内置的Laravel / PHP功能。

If not, I am contemplating between the following approaches and would love to get inputs as to which one is best. 如果没有,我正在考虑以下方法,并希望获得关于哪种方法最好的建议。

A. Create a edit_checkins table with record_id, user_id, timestamp. A.创建一个带有record_id,user_id,时间戳的edit_checkins表。

B. Add a locked_at column to the record table which will hold a timestamp or null (similar to deleted_at column). B.在记录表中添加一个locked_at列,该列将保存一个时间戳或为空(类似于deleted_at列)。

My main concerns is performance & 'garbage collection' since there are times when a record is locked but never actively unlocked. 我主要关心的是性能和“垃圾回收”,因为有时记录被锁定但从未主动解锁。 With approach AI can remove all users locks from the edit_checkins table in a simple query. 使用方法AI可以在一个简单的查询中从edit_checkins表中删除所有用户锁。 However it will be a bit slower when checking if the record is locked since I will have to do a table join (I think it should be negligible since edit event is less often then other events). 但是,在检查记录是否被锁定时,它会稍慢一些,因为我将不得不进行表联接(我认为应该忽略不计,因为edit事件的发生频率低于其他事件)。 With Approach B it is faster to check but I don't get all the info (such as user_id) and it is harder-to-almost-impossible to implement a unlock-all event without knowning the user_id (I'd need to probably add a locked_by column as well to the record). 使用方法B可以更快地进行检查,但我无法获取所有信息(例如user_id),并且在不知道user_id的情况下实现几乎所有解锁事件几乎是不可能的(我可能需要在记录中也添加一个locked_by列)。

I hope I made the question clear enough. 我希望我已经把问题弄清楚了。 Thank you for your time. 感谢您的时间。

What you're trying to do is an application level lock on a record. 您想要做的是对记录进行应用程序级锁定。 You have a business level requirement that only one user can be looking at the edit view of the record at a time. 您有业务级别的要求,一次只能有一个用户可以查看记录的编辑视图。 This "lock" can last seconds, minutes, hours, or whatever max timeout you wish to allow. 此“锁定”可以持续几秒钟,几分钟,几小时或您希望允许的最大超时。

This is completely different then a database level lock on the record. 这与记录上的数据库级别锁完全不同。 The database level lock is required to make sure two update statements don't run on the same record at the same time. 需要数据库级别锁定,以确保两个更新语句不会同时在同一记录上运行。 This lock will only last as long as the transaction takes, which is typically just milliseconds. 此锁定将仅持续进行事务处理的时间,通常只有几毫秒。 Long running or open ended database transactions are not a good idea. 长期运行或开放式数据库事务不是一个好主意。

You're going to need to design your own application logic to do what you want. 您将需要设计自己的应用程序逻辑来执行所需的操作。 I did not see any existing Laravel packages for this. 我没有看到任何现有的Laravel软件包。 There is one called laravel-record-lock , but it does not do what you want to do and it will not persist the lock across multiple requests. 有一个叫做laravel-record-lock ,但是它不执行您想做的事情,并且不会在多个请求之间保持该锁。

I think the most flexible design would be to create a record_locks table, and then create a polymorphic relationship with any model that you would like to be lockable . 我认为最灵活的设计是创建一个record_locks表,然后与您希望可lockable任何模型创建多态关系。 Polymorphic relationship documentation . 多态关系文档 To get you started: 为了帮助您入门:

DB table: 数据库表:

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

Model 模型

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
}

Now you can add the polymorphic relationship to any Model you want to be lockable: 现在,您可以将多态关系添加到要锁定的任何Model中:

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');
    }
}

Finally, use as regular relationships: 最后,用作常规关系:

$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

One final sidenote to address your concern regarding the Query Builder vs Eloquent: the Eloquent Model falls back to the Eloquent Query Builder, and the Eloquent Query Builder falls back to the plain Query Builder. 最后一个补充说明可解决您对“查询生成器”与“口才”的担忧:口才模型退回到了“口才查询”生成器,而“口才查询”生成器又退回到普通的查询生成器。 If you call a method on an Eloquent Model, it attempts to call it on the Eloquent Query Builder. 如果在Eloquent模型上调用方法,则该方法会尝试在Eloquent查询生成器上调用它。 If it doesn't exist there, it attempts to call it on the plain Query Builder. 如果那里不存在,它将尝试在普通查询生成器上调用它。 If it doesn't exist there, you'll get an error. 如果那里不存在,则会出现错误。

So, if you were to do \\App\\User::lockForUpdate() , the method call would eventually filter down to the plain Query Builder (since it doesn't exist on the Eloquent Model or the Eloquent Query Builder). 因此,如果您要执行\\App\\User::lockForUpdate() ,则该方法调用最终将过滤到普通的查询生成器(因为在Eloquent模型或Eloquent查询生成器中不存在)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM