I SQL Server er triggere databaseobjekter, som vil blive eksekveret, når der sker en udløsende hændelse på databasen eller serveren. Triggere spiller en nøglerolle i at opnå forretningskrav som at advare målrettede personer baseret på en opnået tilstand, påbegyndelse af et job eller andre operationer. I den tidligere artikel om DML-triggere talte vi om triggere, typer af triggere og forskellige trigger-muligheder, der er tilgængelige for DML-triggere. I denne artikel vil vi udforske SQL DDL- og LOGON-udløsere.
DDL-udløsere
DDL-triggere kan udløses for en række server- eller databaseomfangede hændelser, herunder både DDL- og DCL-kommandoer. DDL står for Data Definition Language, som bruges til at CREATE, ALTER, DROP alle objekter og DCL står for Data Control Language-sætninger som GRANT, DENY og REVOKE kommandoer. Nedenfor er karakteristikaene for SQL DDL-triggere.
- DDL-udløsere kan oprettes på databaseniveau eller serverinstansniveau, der dækker en bred vifte af DDL-operationer eller DDL-lignende operationer, f.eks. DCL-kommandoer.
- DDL-udløsere kan kun aktiveres eller udløses som en FOR- eller EFTER-triggertype. SQL Server understøtter ikke I STEDET FOR DDL Trigger, og vi kan se, hvordan man forhindrer nogle DDL-operationer via DDL-triggere.
- SQL Server har indbyggede funktioner som EVENTDATA() og IS_MEMBER() til brug inden for DDL-udløsere for at få mere information relateret til udløserhændelser.
- EVENTDATA()-funktionen returnerer fuldstændige detaljer om database- eller serveromfangshændelser i XML-format inden for omfanget af database- eller serveromfanget DDL-udløser eller logon-triggere. EVENTDATA()-funktionen returnerer de komplette hændelsesdetaljer for den session, der udfører DDL- eller logon-aktiviteterne. EVENTDATA() returnerer nedenstående detaljer
- EventType – Type af hændelsen, der udløser DDL-triggeren, der er tilgængelig i tabellen sys.trigger_event_types.
- PostTime – Det tidspunkt, hvor begivenheden blev udløst eller sendt.
- SPID – Sessions-id for begivenheden.
- Servernavn – SQL Server-forekomstnavn, hvor hændelsen blev udløst.
- LoginName – SQL Server-loginnavn, der udførte hændelsen.
- Brugernavn – Brugernavn på login, som vil være dbo som standard.
- DatabaseName – Databasenavn, under hvilket DDL-udløseren blev udløst.
- Skemanavn – Skemanavn på det objekt, der blev påvirket.
- Objektnavn – Objektnavn, som blev påvirket.
- ObjectType – Type af SQL Server-objekt som tabel, visning, lagret procedure.
- TSQLCommand – T-SQL-script, som blev udført af en bruger, som påkaldte DDL-udløseren.
- SetOptions – SET indstillinger brugt af bruger eller klient som SSMS mens TSQLCommand blev udført.
- CommandText – Faktiske DDL- eller DCL-sætninger med DDL-hændelsen angivet i tabellen sys.trigger_event_types.
- IS_MEMBER()-funktionen returnerer, om den aktuelle bruger er medlem af Windows-gruppen eller SQL Server-databaserollen eller ej.
- EVENTDATA()-funktionen returnerer fuldstændige detaljer om database- eller serveromfangshændelser i XML-format inden for omfanget af database- eller serveromfanget DDL-udløser eller logon-triggere. EVENTDATA()-funktionen returnerer de komplette hændelsesdetaljer for den session, der udfører DDL- eller logon-aktiviteterne. EVENTDATA() returnerer nedenstående detaljer
- System DMV sys.triggers gemmer listen over alle databaseomfattede triggere. Vi kan bruge nedenstående forespørgsel til at hente detaljerne for alle databaseomfattede DDL-udløsere.
SELECT * FROM sys.triggersWHERE type ='TR';
- System DMV sys.server_triggers gemmer listen over alle Server-omfangede triggere, og vi kan bruge nedenstående forespørgsel til at hente detaljerne om alle Server-scoped DDL-triggere.
VÆLG * FRA sys.server_triggers;
- DDL Trigger-definitioner kan ses, hvis triggeren ikke er krypteret ved at bruge nogen af nedenstående muligheder fra sys.sql_modules eller ved at bruge OBJECT_DEFINITION()-funktionen eller ved at bruge sp_helptext lagret procedure.
VÆLG OBJECT_SCHEMA_NAME(objekt_id, db_id()) Skemanavn, OBJECT_NAVN(objekt_id) Trigger_Name, definitionFROM sys.sql_modules WHERE object_id =OBJECT_ID(); VÆLG OBJECT_DEFINITION (OBJECT_ID()) SOM ObjectDefinition; EXEC sp_helptext '';
- Alle mulige DDL-hændelser er tilgængelige i tabellen sys.trigger_event_types og kan ses ved hjælp af nedenstående forespørgsel.
VÆLG *FRA sys.trigger_event_types;
Syntaksen for en DDL Trigger er:
OPRET TRIGGER PÅ [ MED [ ,...n ] ] { FOR | EFTER } AS { sql_statement | EKSTERNT NAVN }
Oprettelse af DDL-udløser med databaseomfang
Lad os oprette en Database Scoped trigger for at spore alle tabeloprettelser og logge ind på en logningstabel med navnet Track_DDL_Changes ved hjælp af scriptet nedenfor.
OPRET TABEL Track_DDL_Changes (EventData xml, PostDtm datetime)GOCREATE TRIGGER TR_D_CREATETABLEON DATABASE FOR CREATE_TABLEASBEGIN INSERT INTO Track_DDL_Changes SELECT EVENTDATA(),GETDATE()ENDGO
Lad os oprette en ny tabel med navnet trigger_test og kontrollere, om CREATE TABLE-begivenheden blev revideret eller ej ved at bruge nedenstående script.
CREATE TABLE Trigger_Test (a int, b datetime);
Valg af data fra Track_DDL_Changes-tabellen viser, at ovenstående CREATE_TABLE-hændelse blev fanget med succes som vist nedenfor:
Ved at klikke på EventData-værdien åbnes XML EVENTDATA()-værdien i et nyt vindue som vist nedenfor.
Vi er i stand til at verificere de fuldstændige detaljer om den udløsende hændelse via EVENTDATA()-funktionen, og derfor vil EVENTDATA()-funktionen spille en væsentlig rolle for alle DDL- eller LOGON-triggere.
Vi kan yderligere forbedre vores DDL Trigger ved hjælp af EVENTDATA()-funktionen og XML-parsing og forhindre nogen i at oprette en tabel i testdatabasen ved hjælp af scriptet nedenfor:
CREATE TRIGGER TR_D_PREVENT_CREATETABLEON DATABASEFOR CREATE_TABLEASBEGIN SELECT EVENTDATA().value ('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)') RAISERROR begrænset i denne database ('Created) , Kontakt venligst DBA.', 16, 1) ROLLBACK ENDGO
Oprettelse af en databaseomfanget trigger fuldført med succes, og lad os bekræfte ved at oprette en anden tabel ved hjælp af scriptet nedenfor.
CREATE TABLE Trigger_Test1 (a int, b datetime);
Triggeren har forhindret os i at oprette nye tabeller på denne database og efterladt også en meningsfuld besked til brugerne. Vi kan på samme måde håndtere alle andre DDL- eller Server-omfattede hændelser for at matche kravene.
For at slippe DDL-udløseren med databaseomfang skal vi bruge nedenstående syntaks:
DROP TRIGGER PÅ DATABASE;
Og for at slippe den trigger, vi har oprettet lige nu, ville scriptet være
DROP TRIGGER TR_D_PREVENT_CREATETABLE PÅ DATABASE;
For at se de databaseomfattede DDL-udløsere i SSMS skal du udvide Testdatabasen -> Programmerbarhed -> Databasetriggere som vist nedenfor.
I lighed med SQL DML-udløsere kan DDL-udløsere slettes, deaktiveres eller aktiveres ved blot at højreklikke på triggernavnet som vist nedenfor.
Via T-SQL kan vi droppe eller deaktivere eller aktivere databaseomfattet DDL-udløser ved hjælp af nedenstående syntaks:
-- DROP Database scoped DDL TriggerDROP TRIGGER ON DATABASE;-- Aktiver Database scoped DDL TriggerENABLE TRIGGER ON DATABASE;-- Disable Database scoped DDL TriggerDISABLE TRIGGERON ; kode>
For at deaktivere den trigger, vi har oprettet, skal vi muligvis bruge nedenstående script.
-- DROP Database scoped DDL TriggerDROP TRIGGER TR_D_PREVENT_CREATETABLE ON DATABASE;-- Aktiver Database scoped DDL TriggerENABLE TRIGGER TR_D_PREVENT_CREATETABLE ON DATABASE;-- Disable DATABASE TRIGGER DISABRE DISABRE DISABRE DISABLE TREBTALE_code;
Oprettelse af serveromfanget DDL-udløser
Server scoped DDL trigger følger den samme syntaks svarende til Database scope DDL trigger bortset fra at hændelser vil være baseret på server scope.
Lad os prøve at oprette en serveromfanget DDL-trigger for at forhindre enhver bruger i at oprette en ny database på denne serverinstans ved hjælp af nedenstående script.
CREATE TRIGGER TR_S_PREVENT_CREATEDATABASEPÅ ALLE SERVERFOR CREATE_DATABASEASBEGIN VÆLG EVENTDATA().value ('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)') Databasebegrænsning af ('REISERROR) Eksempel, kontakt venligst DBA.', 16, 1) ROLLBACK ENDGO
Når vi forsøger at oprette en ny database ved hjælp af nedenstående kommando, vil vi modtage en fejl som vist nedenfor.
CREATE DATABASE DATABASE_TEST;
I SSMS, server scoped DDL Triggers under Triggers i Server Objects sektionen som vist nedenfor.
Vi kan droppe, deaktivere eller aktivere den serveromfangede DDL-udløser ved blot at højreklikke på serveromfanget DDL-udløser som vist nedenfor.
Via T-SQL kan vi slette eller deaktivere eller aktivere ved hjælp af nedenstående kommando.
-- DROP Server scoped DDL TriggerDROP TRIGGER TR_S_PREVENT_CREATEDATABASE PÅ ALLE SERVER;-- Deaktiver Server scoped DDL TriggerDISABLE TRIGGER TR_S_PREVENT_CREATEDATABASE PÅ ALLE SERVER;-- Aktiver Server scoped TREVGERENSPREVALLE DDL-TRIGERCODE
Formålet med DDL Triggers
- At revidere alle DDL-hændelser, der sker på tværs af database- eller serverniveau.
- For at forhindre, at DDL-hændelser sker på tværs af database- eller serverniveau.
- At advare, når der sker DDL-hændelser på tværs af database- eller serverniveau.
Login-udløsere
Logon-triggere, som navnet angiver, udføres for LOGON-hændelser i SQL Server. Når godkendelsesfasen er fuldført for en login-hændelse, vil LOGON Trigger-scriptet blive udført ud over login-aktiviteten. Hvis login ikke godkendes korrekt, vil LOGON-udløsere ikke blive udløst. Logon-triggere vil blive vist i SSMS under sektionen Triggers i Serverobjekter. Syntaksen for en LOGON Trigger er som følger:
OPRET TRIGGER PÅ ALLE SERVER{ FOR| EFTER } LOGON AS { sql_statement [; ] [ ,...n ] | EKSTERNT NAVN [; ] }
Opret udløsere
Lad os oprette en simpel LOGON-trigger for at fange flere oplysninger om LOGON-hændelsen fra funktionen EVENTDATA() som vist nedenfor.
OPRET TABEL Track_LOGON_EVENTS (EventData xml, PostDtm datetime)GOCREATE TRIGGER TR_LOGONONON ALLE SERVERFOR LOGONASBEGIN INSERT INTO Track_LOGON_EVENTS SELECT EVENTDATA(),GETDATE();ENDGO
Ovenstående LOGON-trigger vil fange alle detaljer om en login-aktivitet, der ligner det, vi har bemærket, mens vi brugte EVENTDATA()-funktionen i DDL Trigger. Vi bør være forsigtige, når vi planlægger at bruge LOGON-triggere, da hvis der er logiske fejl inde i triggeren, ville det ikke tillade nogen eller de fleste brugere at oprette forbindelse til forekomsten af SQL Server.
For at SLIPPE, deaktivere eller aktivere LOGON-udløsere kan vi bruge nedenstående script.
-- DROP LOGON TriggerDROP TRIGGER TR_LOGON PÅ ALLE SERVERE;-- Deaktiver LOGON TriggerDISABLE TRIGGER TR_LOGON PÅ ALLE SERVER;-- Aktiver LOGON TriggerENABLE TRIGGER TR_LOGON PÅ ALLE SERVER;
Formålet med LOGON-udløsere
- At revidere eventuelle LOGON-hændelser, der sker på serveren.
- For at forhindre, at der sker LOGON-hændelser på serveren
- For at advare, når der sker LOGON-hændelser på serveren.
Trigger-egenskaber
sp_settriggerorder
sp_settriggerorder bruges kun til at definere rækkefølgen af triggerudførelse for den første og sidste trigger. Hvis der er mere end 2 DML-triggere i en tabel, lad os sige 5 DML-triggere, så kan vi definere den første DML-trigger og den sidste DML-trigger, men kan ikke definere rækkefølgen af de midterste 3 triggere.
Bemærk: Indstilling af FIRST eller LAST-indstillingen er specifik for en bestemt hændelseskategori for DML-udløsere. For eksempel i en tabel med 3 INSERT-triggere, kan vi definere, hvilken INSERT-trigger der er FIRST, og hvilken INSERT-trigger der er LAST. Hvis du har 3 triggere på en tabel som INSERT, UPDATE og DELETE, er der ingen grund til at indstille triggerrækkefølgen.
Syntaksen for indstilling af triggerrækkefølgen ville være som denne:
exec sp_settriggerorder @triggername ='' , @order ='FØRST' | 'LAST' , @stmttype ='' , @namespace ='DATABASE' | 'SERVER' | 'NULL'
For DDL-triggere kan vi definere den første og sidste Server Scoped-trigger og derefter definere den første og den sidste Database Scoped-trigger. For eksempel, hvis vi har 5 Server Scoped triggere og 5 Database Scoped triggere, så kan rækkefølgen defineres sådan:
- Første trigger for Server Scoped DDL trigger
- 3 andre serveromfangede DDL-udløsere i tilfældig rækkefølge
- Sidste trigger for Server Scoped DDL trigger.
- Første trigger for Database Scoped DDL trigger (én pr. database)
- 3 Andre DDL-udløsere i tilfældig rækkefølge
- Sidste trigger for Database Scoped DDL trigger.
Med hensyn til indstilling af den første eller den sidste mulighed kan de databaseomfattede DDL-udløsere bestilles i databasen og de serveromfangede DDL-udløsere på instansniveau.
Selvom SQL Server giver os mulighed for at oprette mange triggere på et bord, anbefales det at analysere kravene til triggeren omhyggeligt for bedre vedligeholdelse og fejlfinding.
Rekursive udløsere
SQL Server understøtter også aktivering af udløsere rekursivt for DML-udløsere. Rekursive triggere kan klassificeres som direkte eller indirekte som vist nedenfor.
Direkte rekursive udløsere – Bruger eller applikation opdaterer en post i tabel A. OPDATERING Trigger A i tabel A udløses og opdaterer tabel A igen. Da posten i tabel A blev opdateret via Trigger, vil den igen kalde OPDATERING Trigger A, og dette vil ske rekursivt.
Lad os oprette en direkte rekursive triggere på salgstabellen ved hjælp af nedenstående script:
CREATE TRIGGER TR_UPD_Recursive_Sales ON SalesFOR UPDATE ASBEGIN UPDATE Sales SET SalesDate =GETDATE() WHERE SalesId =(SELECT SalesId FROM Inserted)ENDGO
Udfør nedenstående script:
OPDATERING Salg SET SalesDate =GETDATE() WHERE SalesId =3;
Indirekte rekursive udløsere – Bruger eller applikation opdaterer en post i tabel A. UPDATE-trigger A i tabel A bliver udløst og opdaterer en post i tabel B. Hvis tabel B har en UPDATE-trigger til at opdatere poster tilbage til tabel A, vil den aktivere UPDATE-triggeren i Tabel A, som vil ske rekursivt.
Lad os oprette en indirekte rekursiv trigger på IDR_Test1- og IDR_Test2-tabeller ved hjælp af nedenstående script:
DROP TABLE IDR_Test1DROP TABEL IDR_Test2CREATE TABEL IDR_Test1 (PK int NOT NULL);GOINSERT INTO IDR_Test1 værdier (10),(20)GOCREATE TABEL IDR_Test2 (PK int NOT NULL (PK int NOT NULL);GOINSERT INTO IDR_0EST INTO) )GOCREATE TRIGGER TR_IDR_Test1ON IDR_Test1 FOR UPDATE AS>
Udfør nedenstående script:
OPDATERING IDR_Test1SET PK =1WHERE PK =10;
For at undgå disse former for rekursive triggers påkaldelse på databaseniveau, har SQL Server en mulighed kaldet RECURSIVE_TRIGGERS på hvert databaseniveau for at bryde den rekursive trigger-udløsning. Som standard er indstillingen Rekursiv trigger indstillet til Falsk for en database. Aktiver kun efter behov efter omhyggelig overvejelse af ydeevnepåvirkninger eller dataændringer.
I SSMS skal du højreklikke på vores testdatabase -> Vælg Egenskaber -> Klik på Indstillinger og rul ned for at se indstillingen Rekursive Triggers er aktiveret eller ej som vist nedenfor. For Test Database er den indstillet til False, da False er standardværdien for indstillingen Rekursive Triggers. For at aktivere indstillingen Rekursive Triggers for en specifik database, skal du blot klikke på dropdown-værdien, ændre den til True og klikke på OK.
Via T-SQL kan vi verificere Rekursive Trigger-indstillingen i testdatabasen ved at markere kolonnen is_recursive_triggers_on fra sys.databases DMV som vist nedenfor.
vælg navn, is_recursive_triggers_onfrom sys.databaseswhere name ='test'
For at ændre indstillingen Rekursive triggere for en database (Test i mit eksempel), kan vi udføre nedenstående script.
ALTER DATABASE [Test] SÆT RECURSIVE_TRIGGERS TIL MED NO_WAITGO
For at deaktivere den tilbage til den falske status (standardstatus) for en database (Test i mit eksempel), skal du udføre nedenstående script.
ALTER DATABASE [Test] SÆT RECURSIVE_TRIGGERS FRA MED NO_WAITGO
Indlejrede triggere
Rekursive triggere er et klassisk eksempel på Nested Triggere, men der kan være få andre tilfælde, der resulterer i Nesting af flere triggere. SQL Server tillader indlejring af triggere ned til maksimalt 32 niveauer, og enhver trigger, der overstiger dette indlejringsniveau, vil blive annulleret af SQL Server. SQL Server har en instansdækkende konfiguration til at deaktivere indstillingen Indlejrede triggere. Bemærk venligst, at indlejring af SQL Server-udløsere ved hjælp af CLR-kode eller administreret kode ikke falder ind under grænsen på 32 niveauer, da det er uden for SQL-serverens omfang. Som standard vil indstillingen indlejrede triggere være aktiveret på tværs af alle SQL Server-forekomster, og vi kan deaktivere den efter behov.
Vi kan kontrollere, om indstillingen indlejrede triggere er aktiveret på instansniveau i SSMS ved at følge nedenstående trin:
Højreklik på Server -> Vælg Egenskaber -> Klik på Avanceret
For at deaktivere eller deaktivere indstillingen indlejrede triggere skal du klikke på rullemenuen og ændre den til Falsk og klikke på OK .
Via T-SQL kan vi kontrollere, om indstillingen Nested triggers er aktiveret ved at kontrollere kolonnen value_in_use i sys.configurations DMV for indlejrede triggers konfigurationsnavn.
For at deaktivere denne mulighed skal vi bruge sp_configure den systemlagrede procedure som vist nedenfor:
EXEC sp_configure 'indlejrede udløsere', 0; GÅ GENKONFIGURER; GÅ
Inden for alle DML- eller DDL-triggere, for at finde det aktuelle niveau af nesting, har SQL Server en indbygget funktion kaldet TRIGGER_NESTLEVEL til at returnere antallet af triggere, der udføres for den aktuelle sætning, der udløste triggeren inklusive sig selv. Syntaksen for TRIGGER_NESTLEVEL-funktionen ville være:
VÆLG TRIGGER_NESTLEVEL ( objekt_id, , )
Hvor object_id er triggerens objekt-id, vil trigger_type være AFTER for AFTER trigger og IOT for INSTEAD OF trigger og trigger_event_category vil være enten DML eller DDL.
For eksempel, hvis vi kun skal tillade indlejringsniveau indtil 10 og øge fejlen efter 10 niveauer, så kan vi gøre det på testtrigger som her:
IF ((SELECT TRIGGER_NESTLEVEL(OBJECT_ID('test_trigger'), 'AFTER', 'DML'))> 10) RAISERROR ('Trigger test_trigger indlejret mere end 10 niveauer.',16, -1)
KRYPTERING
For at kryptere triggerlogikken eller definitionen kan WITH ENCRYPTION-indstillingen bruges i triggerdefinition, der ligner alle andre SQL Server-objekter.
UDFØR SOM-klausul
For at udføre triggeren ved hjælp af en specifik sikkerhedskontekst kan EXECUTE AS-sætningen bruges i triggerdefinitionen.
IKKE TIL REPLIKATION
For at identificere, at DML-udløseren ikke skal aktiveres, mens den udføres via replikeringsændringer, vil egenskaben IKKE TIL REPLIKATION blive indstillet for alle objekter i abonnentdatabasen.
Konklusion
Tak, fordi du gennemgik den kraftfulde artikel om DDL-udløsere og logon-triggere, hvor vi har forstået formålet med DDL- og logon-triggere, hvordan man opretter eller dropper, deaktiverer eller aktiverer disse triggere sammen med hvordan man bruger EVENTDATA()-funktionen til sporing af DDL- eller logon-aktiviteter. Derudover har vi lært, hvordan man indstiller udførelsesrækkefølgen for flere SQL DML- eller DDL-triggere sammen med rekursive og indlejrede triggere i detaljer, og hvordan man håndterer rekursive eller indlejrede triggere omhyggeligt.