Редактирование записей базы данных несколькими пользователями

Я разработал таблицы базы данных (нормализованные, на сервере MS SQL) и создал автономный интерфейс Windows для приложения, которое будет использоваться горсткой пользователей для добавления и редактирования информации. Позже мы добавим веб-интерфейс, который позволит осуществлять поиск по нашей производственной области.

Я обеспокоен тем, что если два пользователя начнут редактировать одну и ту же запись, то последний, кто зафиксирует обновление, будет «победителем», и важная информация может быть потеряна. На ум приходит ряд решений, но я не уверен, что собираюсь вызвать еще большую головную боль.

  1. Ничего не делайте и надейтесь, что два пользователя никогда не будут редактировать одну и ту же запись одновременно. - Может и не случится, но что, если случится?
  2. Процедура редактирования может сохранять копию исходных данных, а также обновления, а затем сравнивать, когда пользователь закончит редактирование. Если они отличаются, покажите пользователя и подтвердите обновление - потребуется сохранить две копии данных.
  3. Добавьте последний обновленный столбец DATETIME и проверьте его соответствие при обновлении, если нет, то покажите различия. - требуется новый столбец в каждой из соответствующих таблиц.
  4. Создайте таблицу редактирования, которая регистрирует, когда пользователи начинают редактировать запись, которая будет проверяться и не позволять другим пользователям редактировать ту же запись. - потребует тщательного обдумывания хода выполнения программы, чтобы предотвратить взаимоблокировки и блокировку записей, если пользователь выйдет из программы.

Есть ли какие-то лучшие решения, или я должен выбрать одно из них?

Ответов (8)

Решение

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

Скотт Митчелл написал подробное руководство по реализации этого шаблона: «
Реализация оптимистичного параллелизма».

База данных сделает это за вас. Посмотрите на «выбрать ... для обновления», который предназначен как раз для такого рода вещей. Это даст вам блокировку записи для выбранных строк, которую вы затем можете зафиксировать или откатить.

Со мной, лучший способ иметь столбец lastupdate (тип данных timetamp). при выборе и обновлении просто сравните это значение. Еще одним преимуществом этого решения является то, что вы можете использовать этот столбец для отслеживания времени изменения данных. Я думаю, что это нехорошо, если вы просто создадите столбец вроде isLock для проверки обновлений.

-вначале создать поле (время обновления) для хранения последней записи обновления -когда любой пользователь выберет запись, сохраните время выбора, сравните время выбора и поле времени обновления, если (время обновления)> (время выбора), что означает, что другой пользователь обновит эту запись после выбора записывать

@ Марк Харрисон: 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.
  • когда пользователь начинает редактирование, вы делаете следующее:

    • заблокировать строку (или всю таблицу, если вы не можете заблокировать строку)
    • отметьте флажком строку, которую вы хотите отредактировать
    • если флаг верен, то
      • сообщить пользователю, что он не может редактировать эту строку в данный момент
    • еще
      • установить флаг в значение true
    • отпустить замок

    • при сохранении записи установите флаг обратно в false