Предотвращение одновременного доступа к строкам таблицы db
-
28-10-2019 - |
Вопрос
Иногда случается, что два администратора в нашей группе поддержки пытаются выполнить одну и ту же важную операцию со строкой таблицы db (скажем, изменяя значение в строке). Нам нужно предотвратить это. (Блокировка строк невозможна, потому что таблицы являются "myisam")
Я придумал несколько решений:
установка старого значения в форме и сравнение его с текущим при отправке
родовое словоа затем перед обновлением:
родовое словоно может быть следующая ситуация:
-
пользователю необходимо изменить денежную оценку с 9 долларов на 10 долларов
-
admin1 меняет свои деньги на 10 $
-
пользователь разумно тратит 1 доллар, поэтому его текущие деньги снова становятся 9 долларов!
-
admin2 без предупреждения меняет свои деньги на 10 $.
создание отметки времени (столбец updated_at) в строке
То же самое, что и в решении 1. Преимущество этого подхода в том, что он говорит больше, чем просто сравнение данных. Мы можем точно сказать, были ли данные изменены, пока мы возились с формой, или нет. недостаток - мы не можем отследить, какой именно столбец был изменен, если не объединить его с решением 1
родовое словоа затем при обновлении:
родовое словосоздание временного файла нулевой длины с именем объекта / действия
Создание / блокировка во время обновления и проверка наличие / отметка даты перед обновлением.
Перед обновлением:
родовое словоНа данный момент я предпочитаю создание файлов, потому что:
-
Я думаю, что создать локальный файл быстрее, чем обращаться к базе данных.
-
Мне не нужно добавлять в таблицу еще один столбец (отметку времени)
-
Я могу легко изменить имя файла, чтобы проверить модификацию конкретного столбца, т.е. создать файл "money_user {$ userid} _modified" после завершения mysqlupdate.
Это верно или я что-то неправильно понимаю?
Решение
Вы можете указать старое значение в предложении UPDATE
операции WHERE
, а затем посмотреть количество затронутых строк:
Данный
родовое словоВыполняется поток 1
родовое словоВыполняется поток 2
родовое словоПомимо этого, я бы, вероятно, реализовал исключение немного раньше, назначив сначала задачи отдельным администраторам, чтобы сократить время, которое тратится впустую.
Другие советы
В вашем случае, я полагаю, блокировка - лучший подход.Вы можете использовать блокировки MySQL: GET_LOCK, RELEASE_LOCK, IS_FREE_LOCK.На мой взгляд, транзакции не гарантируют, что строка не изменится, пока другой процесс выполняет свою задачу с извлеченными данными.
Хотя ваш конкретный случай не имеет ничего общего с блокировкой в традиционном смысле.IMHO, вам нужно регистрировать свои транзакции с соответствующими учетными данными и описаниями, чтобы ваши администраторы могли их читать, а не дублировать одну и ту же модификацию баланса.Блокировка может защитить от одновременного изменения строки, но не от намеренного изменения в случае перезаписи.
Я думаю, что блокировка на уровне строк базы данных не соответствует ситуации, о которой вы говорили в первом методе.Но я не думаю, что создание файла быстрее, чем доступ к системе базы данных.Очевидно, что создание файла для базы данных сложнее, чем CRUD.
Итак, я предлагаю аналогичный подход с таблицей журналирования.
- Каждая таблица имеет свой собственный первичный ключ (например,
pid
). - Записывайте имя таблицы и идентификатор идентификатора в таблицу журнала с отметкой времени, когда кто-то пытается изменить строку.
- Перед выполнением запроса проверьте таблицу журнала.
Взгляните на InnoDB и транзакции.Они больше подходят для чувствительных изменений (например, баланса).
Базы данных обычно лучше, поскольку они представляют собой централизованное решение.Если вам необходимо масштабирование из-за трафика или общей рабочей нагрузки, синхронизировать эти файлы будет непросто.Если вы не ожидаете какой-либо необходимости в масштабировании и скорость ввода-вывода хорошая, это нормально.
Позвольте мне упомянуть два возможных решения, о которых вы, возможно, уже упоминали выше.
Вы можете добавить "assign_id" с идентификатором вашей учетной записи администратора в сочетании с отметкой времени, чтобы ваше приложение показывало предупреждение, если его редактирует кто-то другой.
Еще одно возможное решение - проверить, не были ли внесены какие-либо изменения при заполнении форм.Здесь можно использовать метку времени last_edited.