Главная » Microsoft SQL Server, Базы данных » Проектирование блокировок в приложениях

0

Отдельно от блокировок SQL Server следует рассмотреть еще один связанный с этим вопрос. Способ обработки блокировок в приложениях и решение вопросов конкуренции в многопользовательской среде исключительно важны как с точки зрения работы пользователя, так и с точки зрения целостности данных.

Реализация оптимистической блокировки

В работе с многопользовательским доступом существуют два подхода: оптимистическая и пессимистическая блокировки. Выбор любой из них определяет конкретный метод программирования приложения.

Под оптимистической блокировкой понимается то, что пока пользователь работает с данными в форме, другие пользователи имеют к ним доступ. Таким образом, в данном случае, пока какой-либо пользователь работает с данными в клиентском приложении, никакие блокировки не применяются. Блокировка устанавливается только на время записи обновлений в базу. Недостатком оптимистической блокировки является возможность появления потерянных обновлений.

Пессимистическая блокировка использует другой подход, подобный известному закону Мерфи: “Если неприятность может произойти, она случается”. Когда пользователь работает с какими-либо данными, в пессимистической схеме эти данные блокируются.

В то время как пессимистическая блокировка неплохо проявляет себя в небольших рабочих группах в настольных базах данных, большие приложения с архитектурой “клиент/сервер” требуют более высокого уровня конкуренции. Если блокировка SQL Server поддерживается, пока пользователь работает с данными в форме VB или Access, работа приложения будет необоснованно медленной.

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

Потерянные обновления

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

1.              Некий Ваня открыл в клиентском приложении Visual Basic строку товара с кодом 1001. На долю секунды SQL Server применяет общую блокировку для извлечения данных в форму VB,

2.              Таня также открывает строку товара с кодом 1001, используя клиентское приложение.

3.              Оба пользователя — Ваня и Таня— вносят свои изменения в данные о товаре 1001; Ваня исправляет описание товара, а Таня — его категорию.

4.              Ваня сохраняет строку на SQL Server. Инструкция UPDATE заменяет старое описание товара новым, введенным Ваней.

5.              Таня также щелкает на кнопке сохранения, и ее данные также отправляются на сервер в инструкции UPDATE. Категория товара изменяется, но так как в форме Тани было старое описание товара, оно замещает собой новое, сохраненное Ваней.

6.              Ваня обнаруживает ошибку и на очередном совещании жалуется вице-президенту компании на ненадежность базы данных SQL Server.

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

Минимизация потерянных обновлений

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

?               Нормализуйте базу данных так, чтобы она содержала длинные и узкие таблицы. Уменьшая число столбцов в строке, вы снижаете вероятность потерянных обновлений. Например, база данных OBXKites имеет отдельную таблицу для цен. Пользователь может работать с прайс-листом и при этом никак не пресекаться с пользователем, изменяющим другие данные о товарах.

?               Если инструкция UPDATE создается в клиентском приложении, постарайтесь проверять изменения и обновлять только те столбцы, в которых они были фактически выполнены пользователем. Использование этого метода позволило бы избежать потерянных обновлений в приведенном выше примере с Ваней и Таней, а также в большинстве других практических ситуаций. В качестве дополнительного преимущества сокращается трафик между клиентом и сервером и загрузка сервера баз данных.

?               Если схема оптимистической блокировки не позволяет избежать потерянных обновлений, следует использовать принцип “кто последний записал, тот и прав”. Несмотря на то что в этом случае могут возникать потерянные обновления, журнал аудита поможет снизить их эффект. Просматривая обновления, выполненные с одной и той же строкой в течение минуты, вы сможете легко отследить все изменения в данных.

Предотвращение возможности потерянных обновлений

Более строгое решение проблемы потерянных обновлений, чем просто минимизация их эффекта, заключается в использовании метода отслеживания версий. Тип данных rowversion, в ранних версиях SQL Server известный как timestamp, автоматически присваивает новое значение полю при каждом обновлении строки. Сравнивая значение rowversion во время отбора данных для обновления со значением в момент сохранения данных, можно предсказать потерю обновлений с помощью простейшего программного кода.

Метод отслеживания версий может использоваться в инструкциях SELECT и UPDATE. Для этого в предложение WHERE нужно добавить значение rowversion.

В следующем примере продемонстрировано использование методики отслеживания версий с использованием двух пользовательских обновлений. Оба пользователя в клиентском приложении открывают строку с одним и тем же товаром. Обе инструкции SELECT извлекают столбцы RowVersion и ProductName:

SELECT RowVersion, ProductName

FROM Product

WHERE ProductCode = ’10 01′

Будет получен следующий результат:

RowVersion                   ProductName

0x0000000000000077 Basic Box Kite 21 inch

Оба клиентских приложения заполнили формы извлеченными данными. Один из пользователей отредактировал название товара на “Обновление Вани”, и, когда он щелкнул на кнопке сохранения, клиентское приложение выполнило следующую инструкцию SQL:

UPDATE Product

SET ProductName = ‘Обновление Вани1

WHERE ProductCode = ‘1001’

AND RowVersion = 0x0000000000000077

Как только сервер обработал обновление Вани, он автоматически изменил значение RowVersion. Проверяя снова строку, Ваня может увидеть свои обновления:

SELECT RowVersion, ProductName FROM Product

WHERE ProductCode = ’10 01′

Результат следующий:

RowVersion                    ProductName

0x00000000000000B9 Обновление Вани

Если процедура обновления проверяет, не повлияли ли на строку чьи-то обновления, она может увидеть, что изменения Вани были приняты:

SELECT @@ROWCOUNT

В результате будет получено значение 1.

Несмотря на то что значение столбца RowVersion было изменено, клиентское приложение Тани не знает об этом. Когда Таня попытается сохранить свои изменения, ее инструкция UPDATE не найдет строк, удовлетворяющих критерию:

UPDATE Product

SET ProductName = ‘Обновление Тани’

WHERE ProductCode = ‘1001’

AND RowVersion = 0x0000000000000077

Если процедура обновления проверяет, были ли изменены какие-либо строки, то она увидит, что редактирование, выполненное Таней, было проигнорировано:

SELECT @@ROWCOUNT

Результатом будет нуль.

Этот метод может также быть внедрен в приложения, управляемые хранимыми процедурами. Хранимые процедуры fetch и get возвращают значение rowversion наряду с остальными данными строки. Когда приложение VB готово к обновлению и вызывает хранимую процедуру, оно включает rowversion в качестве одного из обязательных параметров. Хранимая процедура update может проверить значение rowversion и выдать ошибку, если два существующих значения не совпадают. Если усложнить этот метод, то хранимая процедура или клиентское приложение может проверить в журнале аудита, не существует ли обновлений столбцов, которые могут привести к потере обновлений, и если это так, сообщить

об        этом последнему пользователю в сообщении об ошибке.

Источник: Нильсен, Пол. Microsoft SQL Server 2005. Библия пользователя. : Пер. с англ. — М. : ООО “И.Д. Вильямс”, 2008. — 1232 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии