Synchronisierte Ausführung der gespeicherten Prozedur in mysql

8

Ich habe eine gespeicherte Prozedur in mysql , die eine Aufgabe ausführt, die synchronisiert werden muss. Wenn zwei Anwendungen die gespeicherte Prozedur aufrufen, kann nur einer auf einen Codeabschnitt zugreifen, um die Aufgabe auszuführen. Der andere bleibt blockiert, bis der erste die Aufgabe beendet hat.

%Vor%

Wenn also zwei Anwendungen die gespeicherte Prozedur gleichzeitig aufrufen, muss die Aufgabe synchronisiert werden.

a. Aber Start TRANSACTION und COMMIT haben die Ausführung NICHT synchronisiert.

b. Und LOCK TABLES tableA kann nicht in gespeicherten Prozeduren verwendet werden, um die Synchronisation zu gewährleisten.

c. Ich habe versucht, den Aufruf der gespeicherten Prozedur auf Anwendungsebene zu synchronisieren. Ich habe

benutzt
  

boost_interprocess bereichssperre ();

Es hat in Bound 1.41

perfekt funktioniert

Aber interprocess locking mutex wird in der Boost 1.34-Bibliothek nicht unterstützt, was in meinem Fall verfügbar ist.

Gibt es eine Möglichkeit, den Codeabschnitt der gespeicherten Prozedur so zu synchronisieren, dass bei zwei gleichzeitig ausgeführten Anrufen blockiert wird, bevor der andere ausgeführt wird?

(hinzugefügt das folgende) bearbeiteter Code: um eine Idee zu geben, was ich im synchronisierten Block der gespeicherten Prozedur auszuführen versuche.

Er erhält die letzte zugewiesene ID, erhöht sie um eins und prüft, ob sie nicht für einen anderen 'Name'-Datensatz verwendet wird. Wenn eine gültige ID gefunden wird, aktualisieren Sie die zuletzt zugewiesene ID-Datensatztabelle und verknüpfen Sie diese dann mit dem angegebenen 'Namen'.

%Vor%     
Flying Dutchman 12.05.2012, 06:16
quelle

2 Antworten

8

Das Starten einer Transaktion mit START TRANSACTION startet es eigentlich nicht. Der erste Tabellenzugriff nach START TRANSACTION funktioniert. Das Öffnen einer Transaktion ist auch kein Mittel zur Steuerung des gemeinsamen Zugriffs. Wenn Sie genau das brauchen, können Sie sich auf das Advisory Locks-System verlassen, das MySQL durch GET_LOCK() , RELEASE_LOCK() und einige andere verwandte Funktionen bereitstellt.

Eine alternative Möglichkeit zur Implementierung der Steuerung des gemeinsamen Zugriffs durch Transaktionen dieses Mal wäre die Verwendung von exklusiven Zeilensperren. Da SELECT -Anweisungen in InnoDB nicht gesperrt sind, wird durch das Ausgeben einer solchen Abfrage eine Transaktion gestartet, jedoch werden weder Sperren noch bereits vorhandene gesperrt. Damit eine SELECT -Anweisung tatsächlich blockiert, wenn eine frühere Transaktion mit derselben Information (Zeile) arbeitet, müssen Sie FOR UPDATE -Klausel verwenden. Zum Beispiel:

%Vor%

Bei dieser Konstruktion gibt es nie zwei gleichzeitige Transaktionen, die mit der gleichen 'NAME_ID' nach der SELECT -Anweisung arbeiten, die explizit angewiesen wurde, eine Sperrlesung durchzuführen.

    
Mushu 12.05.2012, 12:00
quelle
9

Wie in meinen obigen Kommentaren erwähnt, sollten Sie finden , dass eine Transaktion für die meisten Bedürfnisse ausreicht; Wenn Sie jedoch explizit warten müssen, bis der andere Anruf beendet wurde, verwenden Sie GET_LOCK(str,timeout) :

  

Versucht, eine Sperre mit einem Namen zu erhalten, der durch die Zeichenfolge str angegeben wird, wobei ein Zeitlimit von timeout verwendet wird Sekunden. Gibt 1 zurück, wenn die Sperre erfolgreich abgerufen wurde, 0 , wenn der Versuch abgelaufen ist (z. B. weil ein anderer Client den Namen zuvor gesperrt hat) oder NULL , wenn ein Fehler aufgetreten ist (z. B. nicht genügend Arbeitsspeicher oder Thread wurde mit mysqladmin kill getötet. Wenn Sie eine Sperre mit GET_LOCK() erhalten, wird diese bei Ihnen freigegeben Führen Sie RELEASE_LOCK() aus, führen Sie ein neues GET_LOCK() , oder Ihre Verbindung wird beendet (entweder normal oder abnormal). Sperren, die mit GET_LOCK() erzielt wurden, interagieren nicht mit Transaktionen. Das heißt, wenn Sie eine Transaktion festschreiben, werden während der Transaktion keine solchen Sperren ausgelöst.

     

Diese Funktion kann zum Implementieren von Anwendungssperren oder zum Simulieren von Datensatzsperren verwendet werden. Die Namen sind serverweit gesperrt. Wenn ein Name von einem Client gesperrt wurde, blockiert GET_LOCK() jede Anfrage von einem anderen Client für ein Schloss mit dem gleichen Namen. Dadurch können Clients, die einem bestimmten Sperrnamen zustimmen, den Namen für die kooperative Advisory-Sperrung verwenden. Beachten Sie jedoch, dass es einem Client, der nicht zu den kooperierenden Clients gehört, ermöglicht, einen Namen entweder versehentlich oder absichtlich zu sperren und so zu verhindern, dass ein kooperierender Client diesen Namen sperrt. Eine Möglichkeit, die Wahrscheinlichkeit zu verringern, besteht darin, Sperrnamen zu verwenden, die datenbankspezifisch oder anwendungsspezifisch sind. Verwenden Sie beispielsweise Sperrnamen der Form db_name.str oder app_name.str .

%Vor%      

Der zweite Aufruf RELEASE_LOCK() gibt NULL zurück, weil die Sperre aktiviert wurde 'lock1' wurde automatisch vom zweiten GET_LOCK() Aufruf freigegeben.

     

Wenn mehrere Clients auf eine Sperre warten, ist die Reihenfolge, in der sie sie erfassen, nicht definiert und hängt von Faktoren wie der verwendeten Thread-Bibliothek ab. Insbesondere sollten Anwendungen nicht davon ausgehen, dass Clients die Sperre in der Reihenfolge anfordern, in der sie die Sperranforderungen ausgegeben haben.

     
    

Hinweis
    Wenn ein Client vor MySQL 5.5.3 versucht, eine Sperre zu übernehmen, die bereits von einem anderen Client gehalten wird, blockiert er entsprechend dem Argument timeout . Wenn der blockierte Client beendet wird, stirbt sein Thread nicht, bis die Sperranforderung abgelaufen ist.

  
     

Diese Funktion ist für die anweisungsbasierte Replikation nicht sicher. Ab MySQL 5.5.1 wird eine Warnung protokolliert, wenn Sie diese Funktion verwenden, wenn binlog_format wird auf STATEMENT gesetzt. (Fehler # 47995)

    
eggyal 12.05.2012 10:18
quelle