Знакомство с одновременным доступом к данным в ADO.NET
Обновлен: Ноябрь 2007
Когда несколько пользователей пытаются одновременно изменить данные, необходима установка элементов управления для предотвращения взаимного неблагоприятного влияния изменений, внесенных одновременно разными пользователями. Система управления действиями в таких случаях называется управлением параллелизмом.
Типы управления одновременным доступом
Вообще говоря, существует три распространенных способа для управления одновременным доступом в базе данных:
Пессимистическая блокировка: строка недоступна пользователям с момента извлечения записи до момента ее обновления в базе данных.
Оптимистическая блокировка: строка недоступна другим пользователям только во время текущего обновления данных. Обновление проверяет строку в базе данных и определяет наличие изменений. Попытка обновления уже измененной записи вызывает нарушение одновременного доступа.
"Последний побеждает": строка недоступна другим пользователям только во время текущего обновления данных. Однако не предпринимается никаких усилий для сравнения обновлений с текущей записью. Просто выполняется запись с потенциальной потерей любых изменений, сделанных другими пользователями с момента последнего считывания записи вашим приложением.
Пессимистическая блокировка
Пессимистическая блокировка обычно используется по двум причинам. Первая заключается в том, что в некоторых случаях имеет место высокая состязательность за доступ к некоторым записям. Издержки блокировки данных меньше издержек отката изменений при возникновении конфликтов одновременного доступа.
Пессимистическая блокировка также полезна в тех случаях, когда не следует менять запись во время транзакции. Хорошим примером является приложение инвентаризации. Рассмотрим случай проверки запасов представителем компании для потенциального покупателя. Обычно блокировка записи требуется на время создания заказа, вследствие которого элемент помечается как заказанный и удаляется из доступных запасов. Если заказ не создан, блокировка снимается, и другие пользователи, проверяющие запасы, получают точные сведения о доступных запасах.
Однако управление пессимистической блокировкой невозможно в отключенной архитектуре. Подключения открыты только на время чтения данных и их обновления, поэтому блокировки не поддерживаются в течение длительного времени. Кроме того, блокируемое в течение длительного времени приложение не масштабируемо.
Оптимистическая блокировка
При оптимистической блокировке данные блокируются только на время обращения к базе данных. Блокировки препятствуют попыткам других пользователей обновить записи одновременно. Данные всегда доступны, за исключением времени, в течение которого происходит обновление. Дополнительные сведения см. в разделе Оптимистичный параллелизм (ADO.NET).
При попытке обновления исходная версия измененной строки сравнивается с существующей строкой в базе данных. Если строки различаются, обновление отменяется, и выводится ошибка одновременного доступа. Необходимо согласование этих двух строк с помощью созданной пользователями бизнес-логики.
"Последний побеждает"
При использовании способа "последний побеждает" исходные данные не проверяются, а обновления просто записываются в базу данных. Поэтому возможен следующий сценарий действий:
Пользователь А извлекает запись из базы данных.
Пользователь B извлекает ту же запись из базы данных, изменяет ее и записывает обновленную запись в базу данных.
Пользователь A изменяет "старую" запись и записывает ее в базу данных.
В вышеприведенном сценарии изменения, сделанные пользователем B, не видны пользователю A. Если такая ситуация является приемлемой, подход "последний побеждает" можно использовать для управления одновременным доступом.
Управление одновременным доступом в ADO.NET и Visual Studio
В ADO.NET и Visual Studio используется оптимистическая блокировка, поскольку архитектура данных основана на отключенных данных. Поэтому для разрешения проблем, связанных с оптимистической блокировкой, необходима дополнительная бизнес-логика.
При использовании оптимистической блокировки имеется два основных способа определения наличия изменений: метод версии (истинные номера версии или метки даты и времени) и метод сохранения всех значений.
Метод номера версии
При использовании метода номера версии необходимо, чтобы в обновляемой записи имелся столбец, содержащий метку даты и времени или номер версии. Метка даты и времени или номер версии сохраняются у клиента при чтении записи. Это значение затем становится частью обновления.
Одним из способов управления одновременным доступом является выполнение обновления только в случае, если значение в предложении WHERE совпадает со значением в записи. SQL-представление этого подхода выглядит следующим образом:
UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
WHERE DateTimeStamp = @origDateTimeStamp
Кроме того, сравнение можно выполнить с помощью номера версии.
UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
WHERE RowVersion = @origRowVersionValue
Если метки даты и времени или номера версий совпадают, запись в хранилище данных не изменена, и ее можно безопасно обновить, используя новые значения из набора данных. При наличии несоответствий возвращается ошибка. Этот способ проверки одновременного доступа можно применять в Visual Studio. Придется также записать код, чтобы ответить на любые конфликты, связанные с обновлением. Для надежного использования меток даты и времени или номера версии необходимо создать триггер для таблицы, который будет их обновлять при возникновении изменений в строке.
Метод сохранения всех значений
Альтернативой использованию метки даты и времени или номера версии является получение копий всех полей при чтении записи. Объект DataSet в ADO.NET поддерживает две версии каждой измененной записи: исходную версию (которая изначально считывается из источника данных) и измененную версию, содержащую пользовательские обновления. При попытке перезаписи записи в источнике данных исходные значения в строке данных сравниваются с записью в источнике данных. Их соответствие означает, что запись базы данных не была изменена после того, как она была считана. В этом случае измененные значения из набора данных успешно записываются в базу данных.
Каждая команда адаптера данных имеет коллекцию параметров для каждой из четырех команд (DELETE, INSERT, SELECT и UPDATE). Каждая команда имеет параметры как для исходных значений, так и для текущих (или измененных) значений.
![]() |
---|
Для добавления новых записей (команда INSERT) требуются только текущие значения, поскольку не существует исходных записей, а для удаления записей (команда DELETE) требуются только исходные значения для определения местоположения удаляемой записи. |
В следующем примере представлен командный текст для команды набора данных, которая обновляет типичную таблицу Customers. Данная команда задается для динамического SQL и оптимистического параллелизма.
UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName,
ContactTitle = currContactTitle, Address = @currAddress, City = @currCity,
PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFax
WHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL)
AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL)
AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City,
PostalCode, Phone, Fax
FROM Customers WHERE (CustomerID = @currCustomerID)
Обратите внимание, что девять параметров инструкции SET представляют текущие значения, которые необходимо записать в базу данных, тогда как девять параметров инструкции WHERE представляют исходные значения, которые используются для обнаружения исходной записи.
Первые девять параметров в инструкции SET соответствуют первым девяти параметрам в коллекции параметров. Эти параметры имеют свойство SourceVersion, равное Current.
Следующие девять параметров в инструкции WHERE используются для оптимистической блокировки. Необходимо, чтобы эти заполнители соответствовали следующим девяти параметрам в коллекции параметров, а для свойства SourceVersion каждого из этих параметров устанавливалось значение Original.
Инструкция SELECT используется для считывания новых значений в набор данных после обновления. Она создается при установке параметра Обновить набор данных в диалоговом окне Дополнительные параметры генерации SQL.
![]() |
---|
Инструкция SQL, размещенная выше, использует именованные параметры, тогда как команды OleDbDataAdapter используют символ знака вопроса (?) в качестве заполнителя параметра. |
По умолчанию Visual Studio создаст эти параметры, если в Мастере конфигурации адаптера данных выбран параметр Оптимистическая блокировка. Добавление кода для обработки ошибок определяется требованиями пользователей. ADO.NET предоставляет объект DBConcurrencyException, возвращающий строку, нарушающую правила параллелизма. Дополнительные сведения см. в разделе Практическое руководство. Обработка ошибок одновременного доступа.
См. также
Задачи
Практическое руководство. Обработка ошибок одновременного доступа
Основные понятия
Оптимистичный параллелизм (ADO.NET)