Управление транзакциями и оптимистической блокировкой
ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL
Транзакции базы данных обеспечивают безопасную и предсказуемую модель программирования для работы с одновременными изменениями данных. В традиционных реляционных базах данных, таких как SQL Server, вы можете создавать бизнес-логику на основе хранимых процедур и (или) триггеров, которые отправляются на сервер для выполнения непосредственно в ядре СУБД. В традиционных реляционных базах данных вы вынуждены иметь дело с двумя языками программирования — обычный (нетранзакционный) язык приложений, например JavaScript, Python, C#, Java, и отдельный язык для транзакций, например T-SQL, который поддерживается базой данных.
Ядро СУБД Azure Cosmos DB поддерживает транзакции с полной совместимостью с ACID (атомарность, согласованность, изоляция, устойчивость) и изоляцией моментального снимка. Все операции базы данных в области действия логических разделов контейнера выполняются транзакционно в ядре СУБД, которое размещено в реплике раздела. К ним относятся операции записи (обновление одного или нескольких элементов в логическом разделе) и операции чтения. В следующей таблице перечислены различные операции и типы транзакций:
Операция | Тип операции | Транзакция для одного или нескольких элементов |
---|---|---|
INSERT (без предшествующего и последующего триггера) | Write | Транзакция для одного элемента |
INSERT (с предшествующим или последующим триггером) | Запись и чтение | Транзакции для нескольких элементов |
REPLACE (без предшествующего и последующего триггера) | Write | Транзакция для одного элемента |
REPLACE (с предшествующим или последующим триггером) | Запись и чтение | Транзакции для нескольких элементов |
UPSERT (без предшествующего и последующего триггера) | Write | Транзакция для одного элемента |
UPSERT (с предшествующим или последующим триггером) | Запись и чтение | Транзакции для нескольких элементов |
DELETE (без предшествующего и последующего триггера) | Write | Транзакция для одного элемента |
DELETE (с предшествующим или последующим триггером) | Запись и чтение | Транзакции для нескольких элементов |
Выполнение хранимой процедуры | Запись и чтение | Транзакции для нескольких элементов |
Выполнение процедуры слияния, инициируемое системой | Write | Транзакции для нескольких элементов |
Удаление элементов, у которых истек срок жизни (TTL), инициируемое системой | Write | Транзакции для нескольких элементов |
Читать | Читать | Транзакция для одного элемента |
Канал изменений | Читать | Транзакции для нескольких элементов |
Чтение с разбивкой на страницы | Читать | Транзакции для нескольких элементов |
Запрос с разбивкой на страницы | Читать | Транзакции для нескольких элементов |
Выполнение определяемой пользователем функции в составе запроса с разбивкой на страницы | Читать | Транзакции для нескольких элементов |
Транзакции для нескольких элементов
Azure Cosmos DB позволяет создавать хранимые процедуры, предшествующие и последующие триггеры, определяемые пользователем функции и процедуры слияния на языке JavaScript. Ядро СУБД Azure Cosmos DB имеет встроенную поддержку выполнения JavaScript. Вы можете зарегистрировать хранимые процедуры, предзапусковые триггеры, определяемые пользователем функции (UDFS) и процедуры слияния в контейнере, а затем выполнять их транзакционно в ядре СУБД Azure Cosmos DB. Создание логики приложения на JavaScript допускает естественное выражение потока управления, области видимости переменных, присвоения, а также интеграцию примитивов обработки исключений с транзакциями базы данных непосредственно на JavaScript.
Хранимые процедуры, триггеры, определяемые пользователем функции и процедуры слияния на JavaScript помещаются в контекстные транзакции ACID с изоляцией моментального снимка для всех элементов в логическом разделе. Если при выполнении такой транзакции код JavaScript создает исключение, то вся транзакция прерывается и откатывается к прежнему состоянию. Полученная модель программирования является простой, но эффективной. Разработчики JavaScript получают надежную модель программирования, сохраняя привычные языковые конструкции и библиотечные примитивы.
Возможность выполнить код JavaScript непосредственно в ядре СУБД повышает производительность операций над элементами контейнера в базе данных и обеспечивает поддержку транзакций. Кроме того, так как ядро СУБД Azure Cosmos DB изначально поддерживает JSON и JavaScript, не существует несоответствия между системами типов приложения и базы данных.
Управление оптимистичным параллелизмом
Оптимистическая блокировка позволяет предотвратить потери операций обновления и удаления. Для конфликтующих одновременных операций применяется обычная пессимистическая блокировка ядра СУБД, размещенного в том же логическом разделе, что и обрабатываемый элемент. Когда две параллельные операции пытаются обновить элемент в логическом разделе до последней версии, одна из них будет успешной, а вторая завершится ошибкой. Но если одна или обе из таких операций ранее считали старое значение обновляемого элемента, база данных не может проверить актуальность считанных значений для любой из конфликтующих операций. К счастью, с этой ситуацией помогает справиться оптимистическая блокировка, которая не позволит двум операциям одновременно выполнять транзакции в ядре СУБД. Оптимистическая блокировка защищает от случайной перезаписи данные, внесенные другими пользователями. Она также не позволит другим процессам случайно перезаписать ваши изменения.
Реализация управления оптимистической блокировкой с помощью заголовков ETag и HTTP
Каждый элемент, хранящийся в контейнере Azure Cosmos DB, имеет системное свойство _etag
. Значение _etag
создается и обновляется на сервере автоматически при каждом обновлении элемента. Вы можете включить _etag
в заголовок if-match
клиентского запроса, чтобы сервер контролировал возможность условного обновления элемента. Если значение заголовка if-match
совпадает со значением _etag
на сервере, элемент обновляется. Если значение в заголовке запроса if-match
потеряло актуальность, сервер отклоняет операцию и выводит ответное сообщение "HTTP 412: необходимое условие не выполнено". Клиент в этом случае может повторно получить от сервера текущую версию элемента или переопределить сохраненную на сервере версию элемента своим значением _etag
для этого элемента. Кроме того, _etag
в сочетании с заголовком if-none-match
позволяет определить, требуется ли повторное извлечение ресурса.
Значение _etag
изменяется для элемента при каждом его обновлении. В операциях замены элемента значение if-match
следует явным образом включить в параметры запроса. Пример такого кода можно найти на GitHub. Значения _etag
неявно проверяются для всех записываемых элементов, которые затрагиваются в хранимой процедуре. При любом конфликте хранимая процедура выполнит откат транзакции и создаст исключение. Такой метод гарантирует, что операции записи хранимой процедуры применяются атомарным образом, то есть "все или ничего". Приложение получает сигнал о необходимости повторно применить обновления и повторить исходный запрос клиента.
Управление оптимистической блокировкой и глобальное распределение
Для одновременных обновлений элемента Azure Cosmos DB применяет оптимистическую блокировку на уровне протокола связи. Для учетных записей Azure Cosmos DB, настроенных для записи в одном регионе, Azure Cosmos DB гарантирует, что клиентская версия элемента, обновляемого (или удаляемого) совпадает с версией элемента в контейнере Azure Cosmos DB. Это обеспечивает защиту операций записи от случайного изменения чужими записями, и наоборот. В среде с несколькими пользователями оптимистическая блокировка не позволит вам случайно удалить или изменить элемент с неправильной версией. Это обеспечивает защиту от печально известных проблем "потерянного обновления" и "потерянного удаления".
В учетной записи Azure Cosmos DB, настроенной для записи с несколькими регионами, данные могут быть зафиксированы независимо в дополнительных регионах, если они _etag
соответствуют данным в локальном регионе. После того как новые данные будут зафиксированы локально в дополнительном регионе, они объединяются с центральным или основным регионом. Если политика разрешения конфликтов выполнит объединение новых данных с центральным регионом, эти данные будут затем реплицированы глобально с новым значением _etag
. Если политика разрешения конфликтов отклонит новые данные, дополнительный регион будет восстановлен до исходных данных и значения _etag
.
Следующие шаги
Дополнительные сведения о транзакциях базы данных и оптимистической блокировке вы можете получить в следующих статьях.