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
benutztboost_interprocess bereichssperre ();
Es hat in Bound 1.41
perfekt funktioniertAber 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% 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:
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.
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 vontimeout
verwendet wird Sekunden. Gibt1
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) oderNULL
, wenn ein Fehler aufgetreten ist (z. B. nicht genügend Arbeitsspeicher oder Thread wurde mitmysqladmin kill
getötet. Wenn Sie eine Sperre mitGET_LOCK()
erhalten, wird diese bei Ihnen freigegeben Führen SieRELEASE_LOCK()
aus, führen Sie ein neuesGET_LOCK()
, oder Ihre Verbindung wird beendet (entweder normal oder abnormal). Sperren, die mitGET_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
%Vor%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 Formdb_name.str
oderapp_name.str
.Der zweite Aufruf
RELEASE_LOCK()
gibtNULL
zurück, weil die Sperre aktiviert wurde'lock1'
wurde automatisch vom zweitenGET_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 Argumenttimeout
. 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 aufSTATEMENT
gesetzt. (Fehler # 47995)
Tags und Links mysql synchronization stored-procedures locking boost-interprocess