Использование CONTEXT_INFO

Источник: olontsev
olontsev

SQL Server обладает широким набором интересных функций. Одной из них является возможность реализовать передачу определенной информации в пределах одной сессии. Когда это может быть нужно? Например, с одной таблицей в базе данных работает несколько приложений и каждое вводит или изменяет данные с помощью своей хранимой процедуры, а триггер в таблице на изменение данных должен это учитывать и вести себя по-разному для всех приложений. В этом случае как раз можно использовать следующий сценарий: хранимая процедура сохраняет определенное значение в переменной сессии, а триггер считывает это значение и выполняет нужной действие в зависимости от контекста. Также эту технику можно применять при использовании вложенных триггеров (nested triggers).

Переменная сессии CONTEXT_INFO позволяет сохранять данные переменной длины размером до 128 байт. Это немного, но для большинства задач должно хватить. Чтобы установить значение переменной сессии нужно воспользоваться командой SET CONTEXT_INFO, а чтобы получить текущее значение - функцией CONTEXT_INFO(). Ну и сразу приведу небольшой пример.

DECLARE @context_info varbinary(128) SET @context_info = CAST('MyApplicationID1' AS varbinary(128)) SET CONTEXT_INFO @context_info GO   SELECT CONTEXT_INFO() SELECT CAST(CONTEXT_INFO() AS varchar(128)) GO

Между присваиванием значения и его получением я специально поставил разделитель GO, чтобы показать, что параметр сохраняет свое значение даже между разными блоками команд.

Также переменную сессии можно посмотреть в следующих системных представлениях в столбце context_info.

  • sys.dm_exec_requests
  • sys.dm_exec_sessions
  • sys.sysprocesses

Также можно использовать технику, когда в CONTEXT_INFO мы будем хранить не одно, а несколько значений, но в разных местах. Например, мы договариваемся, что в позиции с 1 по 20 мы храним идентификатор процесса, а 21 по 28 - дату и время. Тогда процесс формирования нашей строки будет выглядеть примерно следующим образом.

DECLARE @process_id char(20) = 'MyProcessID2' DECLARE @date_time datetime = GETDATE() DECLARE @context_info varbinary(128)   SET @context_info = CAST(@process_id AS binary(20)) + CAST(@date_time AS binary(8))   SET CONTEXT_INFO @context_info   SELECT CAST(SUBSTRING(CONTEXT_INFO(), 1, 20) AS char(20)) AS process_id, CAST(SUBSTRING(CONTEXT_INFO(), 21, 8) AS datetime) AS date_time

И еще одна небольшая деталь, о которой необходимо помнить: если вы используете CONTEXT_INFO внутри транзакции, то при откате значение не возвращается к исходному. Пример:

DECLARE @context_info varbinary(128) SET @context_info = CAST('Value before transaction' AS varbinary(128)) SET CONTEXT_INFO @context_info SELECT CAST(CONTEXT_INFO() AS varchar(128)) AS [Value before transaction] BEGIN TRAN SET @context_info = CAST('Value inside transaction' AS varbinary(128)) SET CONTEXT_INFO @context_info SELECT CAST(CONTEXT_INFO() AS varchar(128)) AS [Value inside transaction] ROLLBACK SELECT CAST(CONTEXT_INFO() AS varchar(128)) AS [Value after transaction]

Финальным результатом вернется значение, которое мы установили внутри транзакции, несмотря на то, что транзакцию мы откатили. Это нужно учитывать или можно использовать.


Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=36594