Я разработал таблицы базы данных (нормализованные, на сервере MS SQL) и создал автономный интерфейс Windows для приложения, которое будет использоваться горсткой пользователей для добавления и редактирования информации. Позже мы добавим веб-интерфейс, который позволит осуществлять поиск по нашей производственной области.
Я обеспокоен тем, что если два пользователя начнут редактировать одну и ту же запись, то последний, кто зафиксирует обновление, будет «победителем», и важная информация может быть потеряна. На ум приходит ряд решений, но я не уверен, что создам еще большую головную боль.
Есть ли какие-то лучшие решения, или я должен выбрать одно из них?
Если вы ожидаете редких столкновений, вероятно, лучше всего подойдет Оптимистичный параллелизм.
Скотт Митчелл написал подробное руководство по реализации этого шаблона:
.
Реализация оптимистичного параллелизма
База данных сделает это за вас. Посмотрите на «выбрать ... для обновления», который предназначен как раз для такого рода вещей. Это даст вам блокировку записи для выбранных строк, которую вы затем можете зафиксировать или откатить.
@ Марк Харрисон: SQL Server не поддерживает этот синтаксис (SELECT ... FOR UPDATE
).
Эквивалент SQL Server - подсказка оператора SELECT
UPDLOCK
.
См. Электронная документация по SQL Server для получения дополнительной информации.
Другой вариант - проверить, что значения в изменяемой записи остаются такими же, какими они были при запуске:
SELECT
customer_nm,
customer_nm AS customer_nm_orig
FROM demo_customer
WHERE customer_id = @p_customer_id
(отобразить поле customer_nm, и пользователь изменит его)
UPDATE demo_customer
SET customer_nm = @p_customer_name_new
WHERE customer_id = @p_customer_id
AND customer_name = @p_customer_nm_old
IF @@ROWCOUNT = 0
RAISERROR( 'Update failed: Data changed' );
Вам не нужно добавлять новый столбец в таблицу (и поддерживать его в актуальном состоянии), но вам нужно создать более подробные операторы SQL и передать поля новый и Старый в хранимую процедуру.
Это также имеет то преимущество, что вы не блокируете записи - потому что все мы знаем, что записи в конечном итоге останутся заблокированными, когда они не должны быть ...
SELECT FOR UPDATE и его эквиваленты хороши, если вы удерживаете блокировку микроскопическое время, но для макроскопического количества (например, пользователь загрузил данные и не нажал кнопку «сохранить», вам следует использовать оптимистичный параллелизм, как указано выше. Я всегда думаю, что его неправильно называют - это более пессимистично, чем «побеждает последний писатель», что обычно является единственной альтернативой.)
Классический подход заключается в следующем:
когда пользователь начинает редактирование, вы делаете это:
отпустить замок
при сохранении записи установите флаг обратно в false
Хороший замечание, @SilverNight. Можете ли вы опубликовать правильное решение?
Для таких случаев (сбой приложения / браузера) вы можете добавить в приложение метод ForceUnlock, который принудительно установит блокировку на False.
Это решение с белым флагом: "разрешить одновременные модификации сложно, поэтому я собираюсь уйти".
Со мной, лучший способ иметь столбец lastupdate (тип данных timetamp). при выборе и обновлении просто сравните это значение Еще одним преимуществом этого решения является то, что вы можете использовать этот столбец для отслеживания времени изменения данных. Я думаю, что это не хорошо, если вы просто создадите столбец вроде isLock для проверки обновления.
-first create filed (время обновления) для хранения последней записи обновления -когда любой пользователь выбирает запись, выберите время, сравнить между полем выбора времени и времени обновления, если (время обновления)> (время выбора), что означает, что другой пользователь обновит эту запись после выбора записи
Этого недостаточно, если установить lock = true, если приложение или браузер вылетает из строя, то запись навсегда остается мертвой блокировкой.