Heim >Backend-Entwicklung >C#.Net-Tutorial >Redis-Tutorial (8): Detaillierte Erläuterung der Transaktionen
1. Übersicht:
Wie viele andere Datenbanken bietet auch Redis als NoSQL-Datenbank einen Transaktionsmechanismus. In Redis sind die vier Befehle MULTI/EXEC/DISCARD/WATCH der Eckpfeiler unserer Transaktionsimplementierung. Ich glaube, dass dieses Konzept Entwicklern mit Erfahrung in der relationalen Datenbankentwicklung nicht unbekannt ist. Dennoch werden wir die Implementierungsmerkmale von Transaktionen in Redis kurz auflisten:
1). Während der Ausführung der Transaktion stellt Redis keine Dienste für andere Clientanforderungen bereit und stellt so sicher, dass alle Befehle in der Transaktion atomar ausgeführt werden.
2) Im Vergleich zu Transaktionen in relationalen Datenbanken werden nachfolgende Befehle weiterhin ausgeführt, wenn in einer Redis-Transaktion ein Befehl fehlschlägt.
3) Wir können eine Transaktion über den MULTI-Befehl starten, den Personen mit Erfahrung in der relationalen Datenbankentwicklung als „BEGIN TRANSACTION“-Anweisung verstehen können. Die nach dieser Anweisung ausgeführten Befehle werden als Vorgänge innerhalb der Transaktion betrachtet. Schließlich können wir alle Vorgänge innerhalb der Transaktion festschreiben/zurücksetzen, indem wir den Befehl EXEC/DISCARD ausführen. Diese beiden Redis-Befehle können als Äquivalent zur COMMIT/ROLLBACK-Anweisung in einer relationalen Datenbank angesehen werden.
4) Wenn vor dem Start der Transaktion ein Kommunikationsfehler zwischen dem Client und dem Server auftritt und die Netzwerkverbindung unterbrochen wird, werden alle nachfolgend auszuführenden Anweisungen nicht vom Server ausgeführt. Wenn jedoch das Netzwerkunterbrechungsereignis auftritt, nachdem der Client den EXEC-Befehl ausgeführt hat, werden alle Befehle in der Transaktion vom Server ausgeführt.
5). Bei Verwendung des Append-Only-Modus schreibt Redis in diesem Aufruf alle Schreibvorgänge in der Transaktion auf die Festplatte, indem es die Systemfunktion write aufruft. Kommt es jedoch während des Schreibvorgangs zu einem Systemabsturz, beispielsweise bei einem Ausfall durch einen Stromausfall, kann es sein, dass zu diesem Zeitpunkt nur ein Teil der Daten auf die Festplatte geschrieben wird, während ein anderer Teil der Daten verloren geht. Der Redis-Server führt beim Neustart eine Reihe notwendiger Konsistenzprüfungen durch. Sobald ein ähnliches Problem festgestellt wird, wird er sofort beendet und gibt eine entsprechende Fehlermeldung aus. Zu diesem Zeitpunkt müssen wir das im Redis-Toolkit bereitgestellte Tool redis-check-aof vollständig nutzen. Dieses Tool kann uns dabei helfen, Dateninkonsistenzfehler zu lokalisieren und einige der geschriebenen Daten zurückzusetzen. Nach der Reparatur können wir den Redis-Server erneut neu starten.
2. Zugehörige Befehlsliste:
命令原型 | 时间复杂度 | 命令描述 | 返回值 |
MULTI | 用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行EXEC时,这些命令才会被原子的执行。 | 始终返回OK | |
EXEC | 执行在一个事务内命令队列中的所有命令,同时将当前连接的状态恢复为正常状态,即非事务状态。如果在事务中执行了WATCH命令,那么只有当WATCH所监控的Keys没有被修改的前提下,EXEC命令才能执行事务队列中的所有命令,否则EXEC将放弃当前事务中的所有命令。 | 原子性的返回事务中各条命令的返回结果。如果在事务中使用了WATCH,一旦事务被放弃,EXEC将返回NULL-multi-bulk回复。 | |
DISCARD | 回滚事务队列中的所有命令,同时再将当前连接的状态恢复为正常状态,即非事务状态。如果WATCH命令被使用,该命令将UNWATCH所有的Keys。 | 始终返回OK | |
WATCHkey [key ...] | O(1) | 在MULTI命令执行之前,可以指定待监控的Keys,然而在执行EXEC之前,如果被监控的Keys发生修改,EXEC将放弃执行该事务队列中的所有命令。 | 始终返回OK。 |
UNWATCH | O(1) | 取消当前事务中指定监控的Keys,如果执行了EXEC或DISCARD命令,则无需再手工执行该命令了,因为在此之后,事务中所有被监控的Keys都将自动取消。 | 始终返回OK。 |
3. Befehlsbeispiele:
1. Die Transaktion wird normal ausgeführt:
#在Shell命令行下执行Redis的客户端工具。 /> redis-cli #在当前连接上启动一个新的事务。 redis 127.0.0.1:6379> multi OK #执行事务中的第一条命令,从该命令的返回结果可以看出,该命令并没有立即执行,而是存于事务的命令队列。 redis 127.0.0.1:6379> incr t1 QUEUED #又执行一个新的命令,从结果可以看出,该命令也被存于事务的命令队列。 redis 127.0.0.1:6379> incr t2 QUEUED #执行事务命令队列中的所有命令,从结果可以看出,队列中命令的结果得到返回。 redis 127.0.0.1:6379> exec 1) (integer) 1 2) (integer) 1
2. Es gibt einen fehlgeschlagenen Befehl in der Transaktion:
#开启一个新的事务。 redis 127.0.0.1:6379> multi OK #设置键a的值为string类型的3。 redis 127.0.0.1:6379> set a 3 QUEUED #从键a所关联的值的头部弹出元素,由于该值是字符串类型,而lpop命令仅能用于List类型,因此在执行exec命令时,该命令将会失败。 redis 127.0.0.1:6379> lpop a QUEUED #再次设置键a的值为字符串4。 redis 127.0.0.1:6379> set a 4 QUEUED #获取键a的值,以便确认该值是否被事务中的第二个set命令设置成功。 redis 127.0.0.1:6379> get a QUEUED #从结果中可以看出,事务中的第二条命令lpop执行失败,而其后的set和get命令均执行成功,这一点是Redis的事务与关系型数据库中的事务之间最为重要的差别。 redis 127.0.0.1:6379> exec 1) OK 2) (error) ERR Operation against a key holding the wrong kind of value 3) OK 4) "4"
#为键t2设置一个事务执行前的值。 redis 127.0.0.1:6379> set t2 tt OK #开启一个事务。 redis 127.0.0.1:6379> multi OK #在事务内为该键设置一个新值。 redis 127.0.0.1:6379> set t2 ttnew QUEUED #放弃事务。 redis 127.0.0.1:6379> discard OK #查看键t2的值,从结果中可以看出该键的值仍为事务开始之前的值。 redis 127.0.0.1:6379> get t2 "tt"
4. WATCH-Befehl und CAS-basierte optimistische Sperre:
In Redis-Transaktionen kann der WATCH-Befehl verwendet werden, um CAS-Funktionalität (Check-and-Set) bereitzustellen. Gehen Sie davon aus, dass wir mehrere Schlüssel über den WATCH-Befehl überwachen, bevor die Transaktion ausgeführt wird. Wenn sich der Wert eines Schlüssels nach WATCH ändert, wird die durch den EXEC-Befehl ausgeführte Transaktion abgebrochen und eine Null-Multi-Bulk-Antwort zurückgegeben, um den Aufrufer zu benachrichtigen der Transaktion ist fehlgeschlagen. Wir gehen beispielsweise erneut davon aus, dass der Befehl incr in Redis nicht bereitgestellt wird, um die atomare Inkrementierung von Schlüsselwerten abzuschließen. Wenn wir diese Funktion implementieren möchten, können wir nur den entsprechenden Code selbst schreiben. Der Pseudocode lautet wie folgt:
val = GET mykey val = val + 1 SET mykey $val
Der obige Code kann nur garantieren, dass das Ausführungsergebnis bei einer einzelnen Verbindung korrekt ist, da dieser Abschnitt gleichzeitig von mehreren Clients ausgeführt wird Gleichzeitig tritt im Code ein Fehlerszenario auf, das häufig in Multithread-Programmen auftritt – Race Condition (Race Condition). Beispielsweise lesen beide Clients A und B gleichzeitig den ursprünglichen Wert von mykey. Danach addieren beide Clients eins zum Wert und setzen ihn auf den Redis-Server zurück von mykey geht verloren. Das Ergebnis ist 11, nicht 12, wie wir dachten. Um ähnliche Probleme zu lösen, benötigen wir die Hilfe des WATCH-Befehls, siehe folgenden Code:
WATCH mykey val = GET mykey val = val + 1 MULTI SET mykey $val EXEC
Der Unterschied zum vorherigen Code besteht darin, dass der neue Code den Schlüssel vor dem Empfang durch den WATCH-Befehl überwacht Geben Sie den Wert von mykey ein und umgeben Sie dann den Set-Befehl in einer Transaktion. Dadurch kann effektiv sichergestellt werden, dass vor der Ausführung von EXEC für jede Verbindung der aktuelle EXEC-Befehl ausgeführt wird, wenn der von der aktuellen Verbindung erhaltene Wert von mykey von anderen verbundenen Clients geändert wird Die Verbindung kann nicht ausgeführt werden. Auf diese Weise kann der Anrufer nach Beurteilung des Rückgabewerts feststellen, ob val erfolgreich zurückgesetzt wurde.
Das Obige ist der Inhalt des Redis-Tutorials (8): Detaillierte Transaktionen. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)!