Функциональность регистрации / выписки при редактировании записей Laravel 5 (блокировка)

Я использую Laravel 5.1 и пытаюсь реализовать блокировку записи, когда пользователь открывает представление редактирования записи, чтобы любой другой пользователь не мог открыть представление редактирования для той же записи, пока не будет снята блокировка.

Очевидно, что есть случаи, когда пользователь никогда не завершит редактирование, поэтому мне нужно иметь возможность автоматически разблокировать запись (либо когда пользователи совершают какие-либо другие транзакции, либо после события тайм-аута, либо с помощью вызова поддержки активности Ajax-фона).

Я посмотрел в lockForUpdate() и прочитал о функции блокировки InnoDB, но я не смог получить реальную информацию об этом (искал более 20 сообщений, и все они, кажется, читают друг друга без реальной информации). Документы также не предлагают слишком много информации, и изучение кода класса запросов Laravel дало мне следующий прогресс:

  1. Головная боль.
  2. Я понял, что он доступен только в Query Builder (он мне нужен для Eloquent).
  3. Похоже, что это только транснациональная блокировка, а не блокировка регистрации / возврата.

Кажется, что существует большая путаница как с терминологией, так и с тем, что на самом деле делает блокировка mysql (innodb), или это может быть только я, пытаясь понять это.

Короче говоря, главная оговорка с блокировкой InnodDB / Laravel (для моих нужд) заключается в том, что она не постоянна, поэтому она сбрасывается сама, когда скрипт php завершается, а пользователь все еще редактирует форму. Это только для транзакций.

Мне нужно достичь упомянутой функциональности (редактирование регистрации / выписки), и прежде чем я заново изобрету колесо, я хотел бы знать, есть ли уже встроенная функциональность Laravel / PHP для него.

Если нет, я обдумываю следующие подходы и хотел бы узнать, какой из них лучше.

А. Создать edit_checkins таблица с record_id, user_id, отметкой времени.

Б. Добавить locked_at столбец таблицы записей, который будет содержать метку времени или ноль (аналогично deleted_at колонка).

Мои главные проблемы — производительность & «сборка мусора», так как бывают случаи, когда запись заблокирована, но активно не разблокирована. При подходе А я могу удалить все блокировки пользователей из edit_checkins таблица в простом запросе. Однако это будет немного медленнее при проверке, заблокирована ли запись, так как мне нужно будет выполнить объединение таблиц (я думаю, что это должно быть незначительным, так как событие редактирования реже, чем другие события). При использовании подхода B это выполняется быстрее, но я не получаю всю информацию (например, user_id), и практически невозможно реализовать событие unlock-all, не зная user_id (мне, вероятно, потребуется добавить locked_by колонка так же к записи).

Надеюсь, я прояснил вопрос достаточно ясно. Спасибо за ваше время.

1

Решение

То, что вы пытаетесь сделать, это блокировка на уровне приложения для записи. У вас есть требование бизнес-уровня, чтобы только один пользователь мог одновременно просматривать представление редактирования записи. Эта «блокировка» может длиться секунды, минуты, часы или любое другое максимальное время ожидания, которое вы хотите разрешить.

Это полностью отличается от блокировки на уровне базы данных для записи. Блокировка на уровне базы данных необходима для того, чтобы два оператора обновления не выполнялись для одной и той же записи одновременно. Эта блокировка будет длиться столько, сколько длится транзакция, которая обычно составляет всего миллисекунды. Долгосрочные или открытые транзакции базы данных не очень хорошая идея.

Вам нужно будет разработать собственную логику приложения, чтобы делать то, что вы хотите. Я не видел никаких существующих пакетов Laravel для этого. Есть один называется Laravel рекорд-замок, но он не делает то, что вы хотите, и не будет сохранять блокировку для нескольких запросов.

Я думаю, что самым гибким дизайном было бы создать 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

И еще одно последнее замечание, касающееся вашей озабоченности в отношении Query Builder и Eloquent: модель Eloquent возвращается к Eloquent Query Builder, а Eloquent Query Builder — к простому Query Builder. Если вы вызываете метод в Eloquent Model, он пытается вызвать его в Eloquent Query Builder. Если его там нет, он пытается вызвать его в обычном построителе запросов. Если его там нет, вы получите ошибку.

Итак, если вы должны были сделать \App\User::lockForUpdate()вызов метода в конечном итоге будет отфильтрован до простого Query Builder (поскольку он не существует в Eloquent Model или Eloquent Query Builder).

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]