Практика SQL Server

Прикладные блокировки для бизнес-операций

Координируйте обработчики через sp_getapplock, проверяйте коды возврата и отличайте временное исключение от постоянной идемпотентности.

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

Выбор ресурса и времени владения

Назовите минимальную единицу исключительной обработки: например, invoice:481 вместо all-invoices. Глобальное имя ненужно сериализует независимых клиентов. Разное написание, наоборот, создаёт независимые блокировки. Формируйте имя централизованно, включая арендатора, если номера счетов уникальны только внутри него.

Ресурс принадлежит базе и пространству имён принципала базы. Одинаковый текст в разных базах не создаёт общего исключения. Сравнение имён чувствительно к регистру. Используйте каноническое представление и соблюдайте документированную максимальную длину: усечение не должно случайно объединять разные операции.

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

Получение и обязательная проверка

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

IF @@TRANCOUNT <> 0
    THROW 50000, 'This example owns its transaction.', 1;
SET XACT_ABORT ON;
BEGIN TRY
    BEGIN TRAN;
    DECLARE @rc int;
    EXEC @rc = sys.sp_getapplock
        @Resource = N'invoice:481',
        @LockMode = 'Exclusive',
        @LockOwner = 'Transaction',
        @LockTimeout = 5000,
        @DbPrincipal = 'public';
    IF @rc < 0
        THROW 50001, 'Application lock was not acquired.', 1;
    -- Read durable operation record; perform short database work.
    SELECT @rc AS LockResult;
    COMMIT;
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 ROLLBACK;
    THROW;
END CATCH;

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

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

Для проверки откройте транзакцию в A и получите ресурс без завершения. Окно B должно исчерпать время ожидания. Откатите A и повторите B: теперь получение должно пройти. Проверьте также разные номера счетов, которые должны обрабатываться независимо. Обязательно завершите специально оставленную открытой учебную транзакцию.

Постоянные гарантии остаются в данных

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

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

Не держите транзакцию во время обращения к платёжному сервису. Откат SQL не отменяет успешное внешнее списание. Атомарно создайте запись outbox и обрабатывайте её идемпотентным механизмом доставки. Прикладная блокировка может защищать короткий локальный переход, но взаимодействию систем нужен постоянный протокол восстановления.

Если нужны несколько ресурсов, получайте их в одинаковом порядке. Прикладные блокировки тоже участвуют во взаимоблокировках. Измеряйте неудачные получения, длительность ожидания и возраст транзакций. Добавьте испытание с потерей ответа после фиксации: повтор должен вернуть уже записанный итог, а не выполнить работу ещё раз. Отдельно проверьте, что исключение внутри защищённого участка освобождает ресурс после отката. Полезный результат состоит в контролируемой конкуренции одной бизнес-сущности, независимой работе остальных и доказательстве того, что повтор не дублирует завершённый эффект.

Техническая документация: Microsoft Learn: sp_getapplock · Microsoft Learn: sp_releaseapplock.

Вопрос по статье

Есть вопрос по этой теме?

Расскажите, что вы оцениваете или с какой проблемой столкнулись. Мы ответим с практической рекомендацией.

Inquiries are not enabled in this preview.

Задать вопрос по этой статье