Auslöser und Tabellensperre in MySQL

9

Szenario: Ich habe einige Trigger, die die Anzahl der Datensätze einer Tabelle zusammen mit anderen nützlichen Informationen verfolgen. Diese Trigger werden beim Hinzufügen / Löschen / Aktualisieren für diese Tabelle ausgelöst und sorgen dafür, dass diese Informationen in eine andere Tabelle geschrieben werden.

Nun werden diese Trigger in einer Multithread-Umgebung ausgeführt, in der ich möglicherweise gleichzeitig auf Tabellen zugreifen kann. Ich wünschte, ich könnte so etwas machen, aber es ist verboten ( ERROR: Fehlercode: 1314. LOCK ist in gespeicherten Prozeduren nicht erlaubt ):

%Vor%

Die Ziele, die mit diesen LOCKS (oder alternativen Konstrukten) erreicht werden sollen, sind:

  1. Vermeide zwei Trigger, die gleichzeitig laufen, schreibe in die AlarmCount-Tabelle und aktualisiere verwandte Datensätze (ich vermute, dass ich zwei Trigger für verschiedene Datensätze der Alarmtabelle laufen habe, die denselben Datensatz von AlarmCount aktualisieren)
  2. Stellen Sie sicher, dass die AlarmMembership-Tabelle währenddessen nicht geändert wird (z. B. wird die Ziel-MemberId inzwischen gelöscht).

Jeder Rat ist sehr willkommen!

    
DocDbg 17.06.2014, 14:47
quelle

1 Antwort

6

Ich denke, der beste Weg, dies zu handhaben, wäre, das hier beschriebene SELECT ... FOR UPDATE-Muster zu verwenden: Ссылка

Als Referenz:

  

Sehen wir uns ein anderes Beispiel an: Wir haben ein ganzzahliges Zählerfeld in a   Tabelle child_codes, die wir verwenden, um jedem einen eindeutigen Bezeichner zuzuweisen   Kind zum Tisch Kind hinzugefügt. Es ist keine gute Idee, beides zu verwenden   konsistentes Lesen oder Lesen im gemeinsamen Modus zum Lesen des aktuellen Werts von   counter, weil zwei Benutzer der Datenbank dann den gleichen Wert sehen können   für den Zähler, und ein Doppelschlüssel-Fehler tritt auf, wenn zwei Benutzer versuchen   Hinzufügen von Kindern mit demselben Bezeichner zur Tabelle.

     

Hier ist LOCK IN SHARE MODE keine gute Lösung, wenn zwei Benutzer   Lesen Sie den Zähler gleichzeitig, mindestens einer von ihnen endet in   Deadlock, wenn es versucht, den Zähler zu aktualisieren.

     

Um das Lesen und Inkrementieren des Zählers zu implementieren, führen Sie zuerst a   Lesen des Zählers mit FOR UPDATE sperren und dann den Wert erhöhen   Zähler. Zum Beispiel:

%Vor%
  

A SELECT ... FOR UPDATE liest die neuesten verfügbaren Daten, setzt exklusive Sperren für jede Zeile & gt; Es liest. Somit setzt es die gleichen Sperren, die ein gesuchter SQL UPDATE in den Zeilen setzen würde.

. . .

  

Hinweis Das Sperren von Zeilen für die Aktualisierung mit SELECT FOR UPDATE gilt nur   wenn Autocommit deaktiviert ist (entweder durch Starten der Transaktion mit   START TRANSACTION oder indem Autocommit auf 0 gesetzt wird. Wenn Autocommit ist   aktiviert, sind die Zeilen, die der Spezifikation entsprechen, nicht gesperrt.

In Ihrem Fall würden Sie also

ersetzen %Vor%

Mit etwas wie

%Vor%

Ich sage "etwas wie", weil mir nicht ganz klar ist, was OLD.RuleId und OLD.IsResolved referenziert. Auch erwähnenswert von Ссылка ist:

  

Die vorhergehende Beschreibung ist nur ein Beispiel dafür, wie SELECT ... FOR   UPDATE funktioniert. In MySQL, die spezifische Aufgabe, eine eindeutige zu generieren   Bezeichner kann tatsächlich nur mit einem einzigen Zugriff auf   die Tabelle:

%Vor%
  

Die SELECT-Anweisung ruft nur die Kennungsinformationen ab (spezifisch für die aktuelle   Verbindung). Es greift nicht auf eine Tabelle zu.

Mit anderen Worten, Sie können dieses Muster wahrscheinlich noch weiter optimieren, indem Sie nur einmal auf die Tabelle zugreifen ... aber wieder gibt es einige Details zu Ihrem Schema, die ich nicht ganz befolge, und ich bin mir nicht sicher, ob ich das tatsächlich liefern könnte Aussage, die Sie brauchen würden. Ich denke, wenn Sie sich SELECT ... FOR UPDATE anschauen, werden Sie sehen, worauf das Muster hinausläuft und was Sie tun müssen, damit dies in Ihrer Umgebung funktioniert.

Ich sollte auch erwähnen, dass es einige Storage Engine-Umgebungs- und Transaktionsisolationslevel gibt, die Sie berücksichtigen sollten. Es gibt eine sehr, sehr gute Diskussion über SO zu diesem Thema hier: Wann SELECT zu verwenden. .. FÜR UPDATE?

Hoffe, das hilft!

    
evanv 10.07.2014, 14:31
quelle