Защита от одновременного редактирования

Предположим, есть интернет-магазин и два или более менеджеров, которые добавляют и редактируют записи о товарах. И вот, в один прекрасный момент, они решили отредактировать описание одного и того же товара. В 12:00 первый менеджер открывает описание товара в редакторе и начинает вносить изменения (редактирует устаревшую тех. информацию). В 12:05 второй менеджер, также начинает вносить изменения (добавляет описание). В 12:20 первый менеджер нажимает кнопку "записать", проверяет результат своей работы и спокойно продолжает заниматься своими делами. В 12:23 второй менеджер также записывает информацию, не зная, о том, что данные уже успели измениться, с момента их открытия. В итоге - вся внесенная первым менеджером информация безвозвратно заменятся контентом, записанным вторым менеджером, о чем первый менеджер, может и не узнать.

Чтобы не допустить такого варианта развертывания событий, необходимо применять логические блокировки. Только не стоит путать их с блокировкой файлов (php-функция flock()) или таблиц БД (MySQL LOCK TABLE), так как действуют они только то короткое время, пока выполняется скрипт, инициировавший их (забывать про необходимость использования таких блокировок, тоже не стоит). Есть несколько вариантов реализации защиты данных от одновременного редактирования, о которых рассказано ниже.

Защита по времени последнего редактирования

Для реализации схемы защиты данных от одновременного редактирования можно использовать время их последнего изменения. Если данные хрянятся в базе данных, например MySQL, добавляем к таблице дополнительную колонку date_update и записываем в нее каждый раз, при изменении данных, дату и время последнего обновления. Теперь при заходе первого и второго менеджера, записываем каждому из них (в сессию, личные настройки в БД и т.д.) дату последнего изменения описания товара. При записи изменений, проверяем, равна ли дата последнего изменения информации дате, записанной каждому из менеджеров, и если нет, предупреждаем о том, что данные с момента открытия уже подверглись модификации.

При таком методе защиты, второй менеджер, записывающий данные в 12:23 после их модификации первым в 12:20, получит предупреждение о том, что данные уже изменены, так как его контрольное время последней модификации не совпадет с реальным. В этом случае также следует позаботится о сохранности и синхронизации данных, введенных вторым менеджером. К примеру, можно создать новую запись о товаре для второго менеджера.

Защита по времени последнего редактирования + AJAX

В некоторых случаях лучше полностью блокировать данные от изменения, когда с ними уже работает кто-то другой. Для такого метода защиты применяется технология AJAX. При попытке второго менеджера начать редактирование того же товара, которым занимается первый менеджер, второму менеджеру будет отображено предупреждение, что данная информация уже редактируется другим менеджером.

Такая система защиты от одновременного редактирования использует дополнительную колонку БД time_edit, практически идентичную date_update, о которой говорилось выше, плюс еще одну, которую мы назовем redact_on. Новая колонка redact_on, по умолчанию содержит единицу (true), что указывает скрипту, обслуживающему запись данных, на возможность проведения редактирования. При открытии редактора первым менеджером, в redact_on записывается ноль (false), что не позволит открыть форму редактирования менеджеру два.

В процессе редактирования, когда открыта форма редактирования, с помощью технологии AJAX, в колонке time_edit каждый период времени (например 1 минута), прописывается настоящее время (UPDATE table SET time_edit = now() WHERE ...). Это необходимо для того, чтобы в случае некорректного завершения работы менеджером один (закрыто оно браузера, открыта другая страница и др.) отловить ситуацию, когда второй менеджер может приступать к изменениям, невзирая на то, что redact_on = 0.

Также необходимо предусмотреть возможность того, что менеджер, вносящий изменения, может просто куда-то отлучиться, не закрыв предварительно форму для редактирования. Для этого, создается еще одна колонка в БД - last_changes, в которую вносится дата и время последней активности пользователя: если были зарегистрированны движения мышью, нажатия клавиш, то время меняется, иначе остается прежним. Теперь, по прошествию, к примеру тридцати минут с момента последнего обновления last_changes, другой менеджер получает право на редактирование. Перед допуском к редактированию второго менеджера, с помощью все того-же AJAX, необходимо выполнить принудительное автосохранение данных из формы менеджера 1, чтобы не потерять его изменения. Теперь, когда снова появится первый менеджер, ему будет отображено предупреждение о том, что время бездействия превысило определенный порог, и право на редактирование информации передано другому пользователю.

Автосохранение, в принципе, очень полезно, и используя его можно реализовать проверку, активности первого менеджера намного проще. Для этого, каждый раз при автосохранении, которое необходимо выполнять достаточно часто, проверять, были ли внесены какие-либо изменения, относительно прошлого состояния контента? Проверка может быть выполнена при помощи функции PHP mysql_affected_rows(), расположенной в коде сразу за запросом к БД MySQL mysql_query('UPDATE ....'). Если результат выполнения mysql_affected_rows = 0, а это произойдет если все данные в запросе на обновление к БД идентичны уже имеющимся, то через 10-20 минут можно открывать доступ на изменение для другого менеджера, а первому, в случае проявления активности - вывести сообщение о запрете редактирования.

Опубликовано: 2011/06/10
HTML-код ссылки на эту страницу:
<a href="http://petrenco.com/php.php?txt=59" target="_blank">Защита от одновременного редактирования</a>
6153
Комментарии
Хорошая статья и самое интересное, что написана прямо для меня :D Я буквально неделю назад задумался серьёзно над этой проблемой и вот - довольно много идей, как можно эту проблему решить.
Единственное - "Автосохранение, в принципе, очень полезно", но есть одно "НО". Если у нас WYSIWYG, то да - это удобно, но если у нас есть обычные формы и ты случайно удалил нужный текст - то это уже ошибка, так как в браузерах не всегда может помочь ctrl+z, да и не факт, что многие умеют пользоваться этой комбинацией. Тут тогда нужно делать временные копии, что бы можно было восстановить данные.Это было бы удобно - но требует серьёзной работы и не всегда практично - использование этой функции будит очень редка.
Насчёт архитектуры BD таблицы -зачем 4 ячейки:date_update,redact_on,last_changes,time_edit? redact_on - вообще бесполезная ячейка без CRON - так мы смотрим всёравно по дате последнего изменения. date_update,last_changes,time_edit можно сократить до 2-ух.

А вообще спасибо - появилось чёткое видение - как лучше реализовать решение данной проблемы.
Добавить комментарий
Ваш e-mail: (не виден посетителям сайта)
Ваше имя:
Комментарий:
Символы с картинки:
Только выделенные поля формы добавления комментариев обязательны к заполнению.