SQL Server-Triggerschleife

8

Ich würde gerne wissen, ob es überhaupt einen Trigger für zwei Tabellen gibt, die die Daten auf die anderen replizieren.

Zum Beispiel:

  • Ich habe zwei Benutzer-Tabellen, users_V1 und users_V2. Wenn ein Benutzer mit einer der V1-App aktualisiert wird, aktiviert er einen Trigger, der ihn auch in users_V2 aktualisiert.

  • Wenn ich denselben Trigger für die V2-Tabelle hinzufügen möchte, um die Daten in V1 zu aktualisieren, wenn ein Benutzer in V2 aktualisiert wird, wird es in eine Endlosschleife gehen? Gibt es eine Möglichkeit, das zu vermeiden?

Roch 10.02.2010, 14:34
quelle

8 Antworten

8

Ich empfehle nicht, den Trigger während der Verarbeitung explizit zu deaktivieren - dies kann seltsame Nebenwirkungen verursachen.

Die zuverlässigste Methode zum Erkennen (und Verhindern) von Zyklen in einem Trigger ist die Verwendung von CONTEXT_INFO() .

Beispiel:

%Vor%

Siehe diesen Link für ein detaillierteres Beispiel.

Hinweis zu CONTEXT_INFO() in SQL Server 2000:

Kontextinformationen werden unterstützt, aber offensichtlich ist die CONTEXT_INFO Funktion nicht. Sie müssen dies stattdessen verwenden:

%Vor%     
Aaronaught 10.02.2010, 14:52
quelle
6
  • Verwenden Sie entweder TRIGGER_NESTLEVEL () , um die Triggerrekursion einzuschränken, oder

  • Überprüfen Sie die Zieltabelle, ob ein UPDATE überhaupt notwendig ist:

    %Vor%
devio 10.02.2010 15:27
quelle
3

Ich hatte genau das gleiche Problem. Ich habe versucht, CONTEXT_INFO () zu verwenden, aber das ist eine Sitzungsvariable und so funktioniert es nur das erste Mal! Wenn das nächste Mal ein Auslöser während der Sitzung ausgelöst wird, wird dies nicht funktionieren. Also habe ich eine Variable verwendet, die Nest Level in jedem der betroffenen Auslöser zum Beenden zurückgibt.

Beispiel:

%Vor%

Hinweis: Oder verwenden Sie @@ NESTLEVEL & gt; 0, wenn Sie alle verschachtelten Aufrufe stoppen möchten

Eine weitere Anmerkung - In diesem Artikel scheint es viel Verwirrung über verschachtelte Aufrufe und rekursive Aufrufe zu geben. Das ursprüngliche Poster bezog sich auf einen verschachtelten Auslöser, bei dem ein Auslöser einen anderen Auslöser auslösen würde, wodurch der erste Auslöser erneut ausgelöst würde und so weiter. Dies ist verschachtelt, aber laut SQL Server nicht rekursiv, da der Trigger nicht direkt aufrufend / auslösend ist. Rekursion ist NICHT dort, wo "ein Trigger [ist] einen anderen anruft". Das ist verschachtelt, aber nicht unbedingt rekursiv. Sie können dies testen, indem Sie Rekursion und Verschachtelung mit einigen der hier erwähnten Einstellungen aktivieren / deaktivieren: Blogbeitrag zum Verschachteln

    
user290995 10.03.2010 22:22
quelle
1
___ answer2237944 ___
  • Verwenden Sie entweder TRIGGER_NESTLEVEL () , um die Triggerrekursion einzuschränken, oder

  • Überprüfen Sie die Zieltabelle, ob ein UPDATE überhaupt notwendig ist:

    %Vor%
___ qstntxt ___

Ich würde gerne wissen, ob es überhaupt einen Trigger für zwei Tabellen gibt, die die Daten auf die anderen replizieren.

Zum Beispiel:

  • Ich habe zwei Benutzer-Tabellen, users_V1 und users_V2. Wenn ein Benutzer mit einer der V1-App aktualisiert wird, aktiviert er einen Trigger, der ihn auch in users_V2 aktualisiert.

  • Wenn ich denselben Trigger für die V2-Tabelle hinzufügen möchte, um die Daten in V1 zu aktualisieren, wenn ein Benutzer in V2 aktualisiert wird, wird es in eine Endlosschleife gehen? Gibt es eine Möglichkeit, das zu vermeiden?

___ answer2237633 ___

Ich empfehle nicht, den Trigger während der Verarbeitung explizit zu deaktivieren - dies kann seltsame Nebenwirkungen verursachen.

Die zuverlässigste Methode zum Erkennen (und Verhindern) von Zyklen in einem Trigger ist die Verwendung von %code% .

Beispiel:

%Vor%

Siehe diesen Link für ein detaillierteres Beispiel.

Hinweis zu %code% in SQL Server 2000:

Kontextinformationen werden unterstützt, aber offensichtlich ist die %code% Funktion nicht. Sie müssen dies stattdessen verwenden:

%Vor%     
___ answer2421086 ___

Ich hatte genau das gleiche Problem. Ich habe versucht, CONTEXT_INFO () zu verwenden, aber das ist eine Sitzungsvariable und so funktioniert es nur das erste Mal! Wenn das nächste Mal ein Auslöser während der Sitzung ausgelöst wird, wird dies nicht funktionieren. Also habe ich eine Variable verwendet, die Nest Level in jedem der betroffenen Auslöser zum Beenden zurückgibt.

Beispiel:

%Vor%

Hinweis: Oder verwenden Sie @@ NESTLEVEL & gt; 0, wenn Sie alle verschachtelten Aufrufe stoppen möchten

Eine weitere Anmerkung - In diesem Artikel scheint es viel Verwirrung über verschachtelte Aufrufe und rekursive Aufrufe zu geben. Das ursprüngliche Poster bezog sich auf einen verschachtelten Auslöser, bei dem ein Auslöser einen anderen Auslöser auslösen würde, wodurch der erste Auslöser erneut ausgelöst würde und so weiter. Dies ist verschachtelt, aber laut SQL Server nicht rekursiv, da der Trigger nicht direkt aufrufend / auslösend ist. Rekursion ist NICHT dort, wo "ein Trigger [ist] einen anderen anruft". Das ist verschachtelt, aber nicht unbedingt rekursiv. Sie können dies testen, indem Sie Rekursion und Verschachtelung mit einigen der hier erwähnten Einstellungen aktivieren / deaktivieren: Blogbeitrag zum Verschachteln

    
___ qstnhdr ___ SQL Server-Triggerschleife ___ antwort2238190 ___

Ich bin mit dem No-Trigger-Camp für dieses spezielle Design-Szenario. Mit dem begrenzten Wissen darüber, was Ihre App macht und warum es das tut, hier ist meine Gesamtanalyse:

Die Verwendung eines Triggers für eine Tabelle hat den Vorteil, dass alle Aktionen in der Tabelle ausgeführt werden können. Das ist es, Ihr Hauptvorteil in diesem Fall. Das bedeutet jedoch, dass Sie Benutzer mit direktem Zugriff auf die Tabelle oder mehrere Zugriffspunkte auf die Tabelle haben. Ich neige dazu, das zu vermeiden. Trigger haben ihren Platz (ich benutze sie sehr oft), aber es ist eines der letzten Tools für das Datenbankdesign, das ich verwende, weil sie nicht viel über ihren Kontext wissen (im Allgemeinen eine Stärke) und wenn sie dort verwendet werden, wo sie es brauchen um über verschiedene Kontexte und allgemeine Anwendungsfälle informiert zu sein, sind ihre Vorteile geschwächt.

Wenn beide App-Versionen dieselbe Aktion auslösen müssen, sollten sie beide das selbe gespeicherte Proc aufrufen. Der gespeicherte Proc kann sicherstellen, dass die entsprechende Arbeit ausgeführt wird. Wenn Ihre App V1 nicht mehr unterstützen muss, kann dieser Teil des gespeicherten Proc entfernt werden.

Das Aufrufen von zwei gespeicherten Prozeduren in Ihrem Client-Code ist eine schlechte Idee, da dies eine Abstraktionsschicht von Datendiensten ist, die die Datenbank leicht und konsistent bereitstellen kann, ohne dass Ihre Anwendung sich darum sorgt.

Ich bevorzuge es, die Schnittstelle zu den zugrunde liegenden Tabellen mehr zu steuern - entweder mit Ansichten oder UDFs oder SPs. Benutzer erhalten niemals direkten Zugriff auf eine Tabelle. Ein weiterer Punkt hier ist, dass Sie eine einzelne "Benutzer" VIEW oder UDF koaleszieren die entsprechenden zugrunde liegenden Tabellen ohne den Benutzer überhaupt wissen könnte - vielleicht zu dem Punkt, wo nicht einmal "Synchronisation" notwendig ist, da neue Attribute sind in einem EAV-System, wenn Sie diese Art der pathologischen Flexibilität oder in einer anderen Struktur benötigen, die noch verbunden werden kann - sagen OUTER APPLY UDF etc.

    
___ tag123sqlserver ___ Microsoft SQL Server ist ein relationales Datenbankverwaltungssystem (RDBMS). Verwenden Sie dieses Tag für alle SQL Server-Editionen, einschließlich Compact, Express, Azure, Fast-Track, APS (früher PDW) und Azure SQL DW. Verwenden Sie dieses Tag nicht für andere Arten von DBMS (MySQL, PostgreSQL, Oracle usw.). Verwenden Sie dieses Tag nicht für Probleme bei der Software- und mobilen Entwicklung, es sei denn, es steht in direktem Zusammenhang mit der Datenbank. ___ tag123sqlserver2000 ___ Verwenden Sie dieses Tag für Fragen, die für die 2000-Version von Microsoft SQL Server spezifisch sind. Beachten Sie, dass Microsoft ab dem 9. April 2013 diese Version von SQL Server nicht mehr unterstützt, bis sogar Sicherheits-Patches nicht mehr erstellt werden. ___ answer2237517 ___

Sie müssen eine Art Loopback-Erkennung in Ihrem Trigger erstellen. Vielleicht mithilfe einer "if exists" -Anweisung, um zu sehen, ob der Datensatz existiert, bevor er in die nächste Tabelle eingegeben wird. Es hört sich so an, als würde es in eine Endlosschleife gehen, so wie es gerade aufgebaut ist.

    
___ tag123triggers ___ Trigger sind Regeln, die, wenn sie als wahr ausgewertet werden, eine oder mehrere Aktionen ausführen. ___ answer2237523 ___

Rekursion in Triggern, dh ein Trigger, der einen anderen aufruft, ist auf 32 Ebenen

Überprüfen Sie in jedem Trigger, ob die Zeile, die Sie einfügen möchten, bereits existiert.

Beispiel

%Vor%     
___ answer2237529 ___

Vermeiden Sie Trigger wie die Pest .... Verwenden Sie eine gespeicherte Prozedur, um den Benutzer hinzuzufügen. Wenn dies einige Designänderungen erfordert, dann machen Sie diese. Auslöser sind das BÖSE.

    
___ answer2237604 ___

Versuchen Sie etwas wie (Ich habe mich nicht mit dem Create-Trigger-Zeug beschäftigt, da Sie ganz offensichtlich bereits wissen, wie man diesen Teil schreibt):

%Vor%     
___ tag123infiniteloop ___ Eine "Endlosschleife" ist eine Schleife, in der die Ausgangskriterien nie erfüllt werden; Eine solche Schleife würde eine potentiell unendliche Anzahl von Iterationen des Schleifenkörpers ausführen. Das allgemeine Problem zu bestimmen, ob die Ausführung einer Schleife mit gegebenen Vorbedingungen zu einer Endlosschleife führt, ist unentscheidbar; Mit anderen Worten, es gibt keinen Algorithmus, um zu bestimmen, ob eine Ausführung einer Schleife schließlich beendet wird. Dies ist bekannt als das Halteproblem. ___
Cade Roux 10.02.2010 15:54
quelle
0

Sie müssen eine Art Loopback-Erkennung in Ihrem Trigger erstellen. Vielleicht mithilfe einer "if exists" -Anweisung, um zu sehen, ob der Datensatz existiert, bevor er in die nächste Tabelle eingegeben wird. Es hört sich so an, als würde es in eine Endlosschleife gehen, so wie es gerade aufgebaut ist.

    
Aaron 10.02.2010 14:37
quelle
0

Vermeiden Sie Trigger wie die Pest .... Verwenden Sie eine gespeicherte Prozedur, um den Benutzer hinzuzufügen. Wenn dies einige Designänderungen erfordert, dann machen Sie diese. Auslöser sind das BÖSE.

    
Hassan Syed 10.02.2010 14:39
quelle
0

Versuchen Sie etwas wie (Ich habe mich nicht mit dem Create-Trigger-Zeug beschäftigt, da Sie ganz offensichtlich bereits wissen, wie man diesen Teil schreibt):

%Vor%     
HLGEM 10.02.2010 14:48
quelle
0

Rekursion in Triggern, dh ein Trigger, der einen anderen aufruft, ist auf 32 Ebenen

Überprüfen Sie in jedem Trigger, ob die Zeile, die Sie einfügen möchten, bereits existiert.

Beispiel

%Vor%     
Lieven Keersmaekers 10.02.2010 14:38
quelle