Виконання тригерів в певному порядку (исходники), Різне, Програмування, статті

Введення


Проблема, з якою я зіткнувся, досить відома. Я маю дві тригера, які повинні відпрацювати в зумовленому порядку, тобто тригер A повинен виконатися спочатку, а після нього повинен відпрацювати тригер B. Ви можете поцікавитися, а чому б не мати один тригер, який об’єднає тригери A і B в один тригер AB? Хороше питання. На жаль, тригер A використовується для реплікації (For Replication), в той час як більш пізній тригер – не для реплікації, що визначає наявність саме двох тригерів.


Давайте створимо випробувальну середу. Для цього нам знадобляться дві таблиці. Одна – для написання і тестування тригерів, а друга – для журналізації тригера і часу його виконання.


CREATE TABLE [Trigger Priority] (
[Id] [int] IDENTITY (1, 1) NOT NULL ,
[First] [int] NULL ,
[Second] [int] NULL ,
[Last] [int] NULL ,
[Status] [char] (1) NULL
) ON [PRIMARY]
GO


Один тригер буде тригером на вставку, який буде оновлювати стовпець First деяким випадковим числом. Цей тригер буде називатися trg_UpdateFirst


CREATE TRIGGER trg_UpdateFirst ON dbo.[Trigger Priority]
FOR INSERT
AS
declare @id int, @val as float
Select @id = id from inserted
select @val = floor(rand() * 10)
Update [Trigger Priority] set [First] = @val Where ID = @id
Insert into TriggerLog (TriggerName) values (“trg_UpdateFirst”)


Останній рядок тригера журналізірует ім’я тригера і час його спрацьовування в таблиці TriggerLog. Наступний тригер використовується для оновлення стовпця Second значенням зі стовпця First.


CREATE TRIGGER trg_UpdateSecond ON dbo.[Trigger Priority]
FOR INSERT
AS
declare @id int
Select @id = id from inserted
Update [Trigger Priority] set [Second] = [First] Where ID = @id
Insert into TriggerLog (TriggerName) values (“trg_UpdateSecond”)


Останній тригер використовується для оновлення стовпця Last сумою значень стовпців First і Second.


CREATE TRIGGER trg_UpdateLast ON dbo.[Trigger Priority]
FOR INSERT
AS
declare @id int
Select @id = id from inserted
Update [Trigger Priority] set [Last] = [First] + [Second] Where ID = @id
Insert into TriggerLog (TriggerName) values (“trg_UpdateLast”)


Тепер, щоб отримати очікувані результати, тригери trg_UpdateFisrt, trg_UpdateSecond і trg_UpdateLast повинні виконуватися в вищепереліченому порядку. Що ви про це думаєте? Який буде порядок? Випадковим чином або в деякому особливому порядку?


Перш ніж відповісти на це питання, давайте подивимося, що станеться. Після вставки одного запису в таблицю [Trigger Priority] перший стовпець містить п’ятірку, що нормально, і другий теж – 5, що також правильно. Однак в останньому стовпці знаходиться NULL! Чому? Хіба не повинно бути 10?


Тепер давайте перевіримо таблицю TriggerLog. Порядок стовпців – trg_UpdateLast, trg_UpdateFirst і trg_UpdateSecond. Після невеликого дослідження з’ясовується, що тригери виконуються в тому порядку, в якому вони були створені. Таким чином, в ідеалі тригери слід створювати в такому порядку: trg_UpdateFirst, trg_UpdateSecond і trg_UpdateLast. Це ні в якому разі не є простим завданням в силу динамічного характеру процесу розробки, який здебільшого не контролюється розробниками.


Інше питання. Як на більш пізній стадії Ви збираєтеся дізнатися про порядок спрацьовування тригерів?


select * from sysobjects where xType =”TR” order by id


За допомогою вищезгаданого запиту Ви можете ідентифікувати порядок, в якому виконаються тригери.


Встановити порядок


Тепер питання про те, як ми можемо задати порядок виконання. Є зберігається системна процедура, яка для того й існує, щоб відповісти на подібне питання. Ця процедура, що зберігається – sp_settriggerorder. У цієї SP є три параметри.


sp_settriggerorder [@triggername =] “triggername”
, [@ Order =] “значення”
, [@stmttype =] “statement_type”


Перший параметр – це ім’я тригера, а другий параметр – порядок. Цей порядок може приймати одне з трьох значень: “First (перший)”, “None (ні перший, ні останній)”, і “Last (останній)”. Останній параметр являє собою тип тригера, тобто Insert, Update або Delete. Це означає, що Ви не можете дозволити собі мати чотири або п’ять тригерів одного і того ж типу, які б виконувалися в певному порядку. Однак це навряд чи зустрічається в практиці. По крайней мере, я не зустрічав ще так багато тригерів одного типу на одній таблиці.


Цей порядок не може бути встановлений опціями Alter Trigger або Create Trigger. Якщо оператор Alter Trigger змінює перший або останній тригер, то спочатку встановлені на тригері атрибути First або Last віддаляються, і значення замінюється на None. Значення порядку повинно бути переустановлені за допомогою збереженої процедури sp_settriggerorder.


Дозволи


Власник тригера і таблиці, на якій визначено тригер, має дозвіл на виконання sp_settriggerorder. Члени ролей db_owner і db_ddladmin в поточній базі даних, так само як серверна роль sysadmin, можуть виконувати цю збережену процедуру.


Отримання порядку


Наступна проблема полягає у встановленні порядку, в якому виконуються тригери, на більш пізній стадії. Якщо я не помиляюся, немає ніякого прямого способу отримати цю інформацію з Enterprise Manager SQL Server. Замість цього Ви пишете прості запити.


select objectproperty(object_id(” trg_UpdateFirst “), “ExecIsFirstInsertTrigger”) ExecIsFirstInsertTrigger”)


вкаже, чи є trg_UpdateFirst першим (First) тригером на вставку?


Застереження


Коли Ви генеруєте скрипт для тригерів, пріоритет їх спрацьовування не буде заскріптован. Це означає, що Вам доведеться повторно запустити пріоритетні сценарії. Це аргумент на користь відмови від пріоритетних тригерів.


Сервер SQL 2005


У SQL Server 2005 є додатковий параметр в sp_settriggerorder, який повинен повідомити, чи є даний тригер тригером бази даних або тригером сервера. Це обумовлено тим, що в SQL Server 2005 Ви можете написати також DDL тригери.


Висновок


Установка пріоритетного порядку для тригера SQL Server не складає труднощів. Однак Ви повинні взяти на себе додаткову турботу, приймаючи цю можливість в структурі вашої розробки. Буде добре, якщо Microsoft може забезпечити рішення для розглянутих вище проблем.

Dinesh Asanka (Оригінал: Triggers to Execute in Pre Defined Order)
Переклад: Моісеєнко С.І.
Оригінал перекладу

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*