einführen In einem verteilten System ist die verteilte Sperre die grundlegendste Werkzeugklasse. Wenn beispielsweise zwei Mikrodienste mit Zahlungsfunktionen bereitgestellt werden, kann ein Benutzer zwei Zahlungsvorgänge für eine Bestellung initiieren und diese beiden Anforderungen können an zwei Dienste gesendet werden. Daher muss eine verteilte Sperre verwendet werden, um doppelte Übermittlungen zu verhindern. Der Dienst, der die Sperre erhält, führt den Zahlungsvorgang normal aus, und der Dienst, der die Sperre nicht erhält, fordert zu doppelten Vorgängen auf. Unser Unternehmen hat eine große Anzahl grundlegender Werkzeugklassen gekapselt. Wenn wir verteilte Sperren verwenden möchten, müssen wir nur drei Dinge tun: 1. Erstellen Sie eine Globallocktable-Tabelle in der Datenbank Nachdem Sie diesen Artikel gelesen haben, können Sie auch Springboot-Starter verwenden, um dieselbe Funktion zu erreichen. Aber wir haben es nicht so umgesetzt. Wir werden einen weiteren Artikel schreiben, um zu analysieren, wie wir es umgesetzt haben. Dieser Artikel analysiert zunächst die Implementierung der MySQL-Verteilung Erstellen einer Tabelle TABELLE „globallocktable“ erstellen ( `id` int(11) NICHT NULL AUTO_INCREMENT, `lockKey` varchar(60) NOT NULL COMMENT 'Sperrname', `createTime` datetime NICHT NULL KOMMENTAR 'Erstellungszeit', Primärschlüssel (`id`), EINZIGARTIGER SCHLÜSSEL `lockKey` (`lockKey`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Globale Sperre'; Komponenten zur Verwendung durch andere @Komponente öffentliche Klasse GlobalLockComponent { @Ressource GlobalLockTableDAO globalLockDAO; /** * Versuchen Sie, die Sperre zu erhalten. „true“ bei Erfolg, „false“ bei Fehlschlag */ öffentliches Boolean tryLock(String-Schlüssel) { gibt GlobalLockUtil.tryLock(this.globalLockDAO, Schlüssel) zurück; } /** * Wenn ein anderes Programm die Sperre belegt hat und das Timeout (Millisekunden) überschritten wird, wird die Sperre zwangsweise aufgehoben. * Das heißt, zuerst den Datensatz entsprechend dem Schlüssel löschen und dann den Datensatz hinzufügen */ öffentliche boolean tryLockWithClear(String-Schlüssel, Long timeoutMs) { gibt GlobalLockUtil.tryLockWithClear zurück (this.globalLockDAO, Schlüssel, TimeoutMs); } /** * Sperre aufheben und Datensatz laut Schlüssel löschen */ public void releaseLock(String-Schlüssel) { GlobalLockUtil.releasLock(this.globalLockDAO, Schlüssel); } } Das Sperrobjekt wird wie folgt definiert öffentliche Klasse GlobalLockTable { private Integer-ID; private Zeichenfolge „lockKey“; privates Datum, Erstellungszeit; // Get- und Set-Methoden weglassen} GlobalLockTableDAO ist wie folgt definiert: öffentliche Schnittstelle GlobalLockTableDAO { int deleteByPrimaryKey(Integer-ID); : In diesem Beispiel wird die Zeichenfolge deleteByLockKey als Schlüsselwert für die Anweisung deleteByLockKey verwendet. : GlobalLockTable selectByLockKey (String-Schlüssel); int insertSelectiveWithTest(GlobalLockTable-Datensatz); } Spezifische Sperr- und Entsperrlogik öffentliche Klasse GlobalLockUtil { privater statischer Logger logger = LoggerFactory.getLogger(GlobalLockUtil.class); private static GlobalLockTable tryLockInternal(GlobalLockTableDAO lockDAO, String key) { GlobalLockTable einfügen = neue GlobalLockTable(); einfügen.setCreateTime(neues Datum()); einfügen.setLockKey(Schlüssel); // Anmerkung 1 int count = lockDAO.insertSelectiveWithTest(einfügen); wenn (Anzahl == 0) { GlobalLockTable bereit = lockDAO.selectByLockKey(Schlüssel); logger.warn("kann den Schlüssel nicht sperren: {}, {}, {}", insert.getLockKey(), ready.getCreateTime(), bereit.getId()); Rückkehr bereit; } logger.info("ja, habe das Schloss mit dem Schlüssel erhalten: {}", insert.getId(), insert.getLockKey()); gibt null zurück; } /** Zeitüberschreitung zum Aufheben der Sperre und erneuten Sperren**/ öffentliche statische Boolesche tryLockWithClear (GlobalLockTableDAO lockDAO, String-Schlüssel, Long timeoutMs) { GlobalLockTable-Sperre = tryLockInternal (lockDAO, Schlüssel); wenn (Sperre == null) true zurückgeben; wenn (System.currentTimeMillis() - lock.getCreateTime().getTime() <= timeoutMs) { logger.warn("Entschuldigung, kann den Schlüssel nicht abrufen. : {}, {}, {}", key, lock.getId(), lock.getCreateTime()); gibt false zurück; } logger.warn("für den Schlüssel ist bereits vorher eine Zeitüberschreitung aufgetreten: {}, {}, wird gelöscht", key, timeoutMs); // Anmerkung 2 : In diesem Fall ist lockDAO.deleteByPrimaryKey die einzige Funktion, die lock.getId() verwendet. wenn (Anzahl == 0) { logger.warn("Entschuldigung, der Schlüssel wurde bereits von anderen vorweggenommen: {}, {}", lock.getId(), lock.getLockKey()); gibt false zurück; } Sperre = tryLockInternal(lockDAO, Schlüssel); Sperre zurückgeben != null? false : true; } /** Sperren **/ öffentliche statische Boolesche tryLock (GlobalLockTableDAO lockDAO, String-Schlüssel) { returniere tryLockInternal(lockDAO, key) == null ? true : false; } /** Entsperren **/ öffentliche statische Leere freigebenLock (GlobalLockTableDAO lockDAO, String-Schlüssel) { lockDAO.deleteByLockKey(Schlüssel); } } An dieser Tool-Klasse sind zwei Dinge besonders interessant. Schauen wir uns zunächst Punkt 2 an (im obigen Code markiert) 1. Um zu vermeiden, dass die Sperre längere Zeit nicht freigegeben wird, können Sie bei der Implementierung mit Redis ein Sperrtimeout festlegen. Nach Ablauf des Timeouts wird die Sperre automatisch freigegeben (ich werde später darüber schreiben, wie verteilte Sperren mit Redis implementiert werden). Wenn es mit MySQL implementiert wird, können Sie es zuerst löschen und dann hinzufügen. Man sieht, dass beim Löschen die ID und nicht der Name zum Löschen verwendet wird. Warum? Denken Sie zuerst darüber nach Denn wenn Sie es namentlich löschen, ist es möglich, dass jemand anderes die Sperre gelöscht und dann vor Ablauf der Zeitüberschreitung eine namentliche Sperre hinzugefügt hat, Sie diese jedoch namentlich gelöscht haben. Wenn Sie nach ID löschen und die zurückgegebene ID = 0 ist, bedeutet dies, dass jemand anderes es erneut gesperrt hat und Sie es erneut abrufen müssen. 2. Die anderen Methoden der GlobalLockTable-Objekt-Dao-Ebene sind selbsterklärend. Schauen wir uns diese Methode einmal an. Das heißt, Anmerkung 1 im Code Die Funktion von insertSelectiveWithTest besteht darin, den Einfügevorgang nicht auszuführen, wenn lockKey vorhanden ist, und 0 zurückzugeben. Wenn der Sperrschlüssel nicht existiert, führen Sie eine Einfügeoperation aus und geben Sie 1 zurück. <insert id="insertSelectiveWithTest" useGeneratedKeys="true" keyProperty="id" parameterType="com.javashitang.middleware.lock.mysql.pojo.GlobalLockTable"> einfügen in `globallocktable` (`id`, `Schlüsselsperre`, `Zeiterstellung` ) wählen Sie #{id,jdbcType=INTEGER}, #{lockKey,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP} von dual, wo nicht existiert (Wählen Sie 1 aus der Globallock-Tabelle, wobei LockKey = #{lockKey,jdbcType=VARCHAR}) </einfügen> verwenden Wenn wir es verwenden möchten, müssen wir nur die Geschäftslogik schreiben, was sehr praktisch ist. wenn (!globalLockComponent.tryLock(name)) { //Zurück, wenn die Sperre nicht erworben wurde; } versuchen { // Schreiben Sie hier die Geschäftslogik} catch (Exception e) { Endlich globalLockComponent.releasLock(Name) Zusammenfassen Das Obige ist die Einführung des Herausgebers in die Verwendung von MySQL zum Implementieren einer verteilten Sperre. Ich hoffe, es wird für alle hilfreich sein! Das könnte Sie auch interessieren:
|
<<: JavaScript-Wissen: Konstruktoren sind auch Funktionen
>>: So kopieren Sie schnell große Dateien unter Linux
Vorwort Es besteht ein Missverständnis bezüglich ...
Der spezifische Code zum Senden von Emoticons im ...
Die Rich-Text-Komponente ist eine sehr häufig ver...
Lassen Sie uns zunächst den Netzwerkeinstellungsm...
1. Voraussetzungen Bei der Entwicklung von Front-...
Problembeschreibung MySQL wurde erfolgreich gesta...
Inhaltsverzeichnis Einführung Vier Merkmale von T...
In Node.js ist eine .js-Datei ein vollständiger B...
1.1 Allgemeine Kennzeichnung Ein allgemeines Tag ...
Inhaltsverzeichnis 1. Wenn die Maus über das Karu...
Inhaltsverzeichnis Vorwort Untergeordnete Kompone...
js-Arrays sind wahrscheinlich jedem bekannt, da s...
Warum erzielen wir diesen Effekt? Tatsächlich wir...
1. Grundlinien 2. Spezialeffekte (die Effekte sin...
In diesem Artikelbeispiel wird der spezifische Co...