Der Inhalt dieses Artikels befasst sich mit dem Vergleich von MySQL- und Redis-Transaktionen (Bilder und Texte). Ich hoffe, dass er für Sie hilfreich ist.
Kurz gesagt: Im Allgemeinen müssen Transaktionen vier Bedingungen (ACID) erfüllen: Atomizität (ATomizität oder Unteilbarkeit), Konsistenz (CKonsistenz), Isolation ( ISolation, auch Unabhängigkeit genannt), Dauerhaftigkeit (DDurabilität).
Was ist dem Titel nach zu urteilen, da es sich bei beiden um Affären handelt, was ist der Unterschied zwischen ihnen? Lassen Sie uns sie einzeln entschlüsseln, beginnend mit den beiden Datenbanken.
MySQL gehört zu 关系型数据库
und Redis gehört zu 非关系型数据库
. Sie haben unterschiedliche Interpretationen von Transaktionen.
(Verwandte Empfehlungen: MySQL-Tutorial, Redis-Tutorial)
[1] Redis-Transaktionen können mehrere Transaktionen ausführen auf einmal und verfügt über die folgenden zwei wichtigen Garantien:
Eine Transaktion durchläuft vom Start bis zur Ausführung die folgenden drei Phasen:
Die Ausführung eines einzelnen Redis-Befehls ist atomar, aber Redis fügt keinen Mechanismus zur Aufrechterhaltung der Atomizität der Transaktion hinzu, sodass die Ausführung der Redis-Transaktion nicht atomar ist.
Eine Transaktion kann als gepacktes Batch-Ausführungsskript verstanden werden, aber Batch-Anweisungen sind keine atomaren Operationen. Der Fehler einer Anweisung in der Mitte führt nicht zum Rollback der vorherigen Anweisungen. Es führt nicht dazu, dass nachfolgende Anweisungen nicht ausgeführt werden.
Es scheint etwas kompliziert zu sein, also führen wir es tatsächlich aus und sehen uns das Ergebnis an.
127.0.0.1:6379> multi OK 127.0.0.1:6379> set tr_1 233 QUEUED 127.0.0.1:6379> lpush tr_1 666 QUEUED 127.0.0.1:6379> set tr_2 888 QUEUED 127.0.0.1:6379> exec 1) OK 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value 3) OK
In der obigen Transaktion werden Zeichenfolgendaten mit dem Schlüssel tr_1
festgelegt und dann werden Elemente über lpush
hinzugefügt. Dies ist offensichtlich die falsche Vorgehensweise, wenn wir die Transaktion A übermitteln 操作错误
erscheint. Schauen wir uns nun den Wert von tr_1
an.
127.0.0.1:6379> get tr_1 "233"
Der durch den get
-Befehl erhaltene tr_1
-Inhalt ist immer noch 233 und hat sich nicht geändert.
127.0.0.1:6379> keys * 1) "tr_2" 2) "tr_1" 127.0.0.1:6379> get tr_2 "888" 127.0.0.1:6379>
Hier können Sie sehen, dass tr_2
vorhanden ist und der Wert gedruckt wird. Zu diesem Zeitpunkt haben wir festgestellt, dass der Fehler nicht 操作错误
ohne aufgetreten ist, obwohl aufgetreten ist Die Ausführung wird gestoppt. Die Anweisung wurde ebenfalls erfolgreich ausgeführt. Es scheint nicht mit dem oben genannten übereinzustimmen dazu führen, dass die nachfolgenden Anweisungen nicht ausgeführt werden.
NEIN~, derzeit liegt eine andere Situation vor语法错误
127.0.0.1:6379> multi OK 127.0.0.1:6379> set tr_1 233 QUEUED 127.0.0.1:6379> lpush tr_1 666 QUEUED 127.0.0.1:6379> set (error) ERR wrong number of arguments for 'set' command 127.0.0.1:6379> set 233 (error) ERR wrong number of arguments for 'set' command 127.0.0.1:6379> set tr_2 888 QUEUED 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> keys * (empty list or set)
Wenn wir set
ausführen, werden keine Parameter angegeben. Bei der zweiten Ausführung wurde bewusst ein Parameter angegeben. Sie können sehen, dass 语法错误
gemeldet und die Transaktion schließlich übermittelt wurde, was uns auch mitteilte, dass die Transaktion aufgrund eines Fehlers verloren gegangen ist. Dann haben wir mit keys *
gesucht und festgestellt, dass dies tatsächlich der Fall war.
Hier finden Sie diejenigen, die im offiziellen Dokument erwähnt werden
Fehler innerhalb einer Transaktion
// Sie können währenddessen auftreten Ausführung zu zwei falschen Befehlsfehlern.
Während einer Transaktion können zwei Arten von Befehlsfehlern auftreten:
//
1
Der Befehl kann nicht in die Warteschlange gelangen, wie zum Beispiel: falsche Anzahl von Parametern, falscher Befehlsname ... oder einige kritische Fehler wie unzureichender Speicher
- Ein Befehl kann möglicherweise nicht in die Warteschlange gestellt werden, sodass möglicherweise ein Fehler auftritt, bevor EXEC aufgerufen wird. Beispielsweise ist der Befehl möglicherweise syntaktisch falsch (falsch). Anzahl der Argumente, falscher Befehlsname usw.) oder es liegt möglicherweise ein kritischer Zustand vor, z. B. nicht genügend Speicher (wenn der Server mithilfe der
maxmemory
-Anweisung so konfiguriert ist, dass er ein Speicherlimit hat).//
2
. Falsche Operationen an Schlüsseln, wie z. B. die Verwendung von lpush für die oben genannten Zeichenfolgen
- Ein Befehl schlägt möglicherweise fehl, nachdem EXEC aufgerufen wurde, zum Beispiel seit wir ausgeführt haben eine Operation für einen Schlüssel mit dem falschen Wert (wie das Aufrufen einer Listenoperation für einen Zeichenfolgenwert).
// Der Client überprüft den eingegebenen Befehl und findet meistens
exec
vor dem Aufruf it 🎜>Fehler. Wenn die Befehlsausführung QUEUED zurückgibt, bedeutet dies, dass der Befehl normal in die Warteschlange gelangt. Andernfalls wird der Client die Transaktion beenden und abbrechen.第一类
Clients used to sense the first kind of errors, happening before the EXEC call, by checking the return value of the queued command: if the command replies with QUEUED it was queued correctly, otherwise Redis returns an error. If there is an error while queueing a command, most clients will abort the transaction discarding it.
关于 Redis 暂时看到这里 接下来看到 MySQL
众所周知,MySQL 只有 InnoDB 引擎
支持 事务,在启用 MySQL 事务之前需要先停掉自动提交
user
列 | 类型 | 注释 |
---|---|---|
id | int(11) 自动增量 | 主键ID |
money | int(11) [0] | 金钱 |
title | varchar(500) NULL | 称呼 |
在这里来模拟一个转账的操作:A
给B
转100元
。
步骤解析 A
+100 元,B
-100元,即两步虽然很简单,简单走一下流程。
可以看到,没有问题,那么我们从中人为的制造一些问题呢?
列 | 类型 | 注释 |
id | int(11) 自动增量 | |
money | int(11) unsigned [0]
|
|
title | varchar(500) NULL |
这里我们把 money
字段变成了无符号,即不能小于 0,并且,调整数据库中的数据如下。
`SELECT * FROM `user` LIMIT 50` (0.000 秒)
修改 | id | money | title |
---|---|---|---|
编辑 | 1 | 10000 | A |
编辑 | 2 | 0 | B |
接着执行下面的 SQL
select version(); SET AUTOCOMMIT=0; begin; select * from user where title in ('A','B') for update; update user set money = money + 1000 where title = 'A'; update user set money = money - 1000 where title = 'B'; select * from user where title in ('A','B'); commit;
问题出现了,这里报出了错误,但是可以看到 前面的 SQL 已经是已执行的了,结果已经发生了变化,从这里看,似乎和 Redis 的处理差不多,除了错误之后语句继续执行。但是 值的注意的是, 在我们实际开发中,这种情况程序会直接抛出异常,以供我们在 catch 块中执行 rollback ,以回滚操作确保数据完整,即使是单独使用 MySQL 命令行 我们也可以用存储过程来对异常进行回滚。
刚刚看到 Redis 当遇到 语法错误
时会自动丢弃事务,阻止提交,那 MySQL 呢?
答案:不会
,MySQL 在顺序执行时,如果未对异常进行处理,总会将成功执行的的提交,而不会触发自动终止,但是我们可以在程序执行时进行放弃提交。
Redis 的官方文档给出了这样的解释
// 只有在使用错误的语法调用时才会失败Redis命令(并且在命令排队期间无法检测到问题),或者对于持有错误数据类型的键,Redis命令可能会失败:这意味着实际上失败的命令是编程错误的结果,以及在开发过程中很可能检测到的一种错误,而不是在生产中。
- Redis commands can fail only if called with a wrong syntax (and the problem is not detectable during the command queueing), or against keys holding the wrong data type: this means that in practical terms a failing command is the result of a programming errors, and a kind of error that is very likely to be detected during development, and not in production.
// Redis内部简化且速度更快,因为它不需要回滚的能力。
- Redis is internally simplified and faster because it does not need the ability to roll back.
数据库 自动回滚条件 | 操作错误 | 语法错误 |
---|---|---|
MySQL | ✖ | ✖ |
Redis | ✖ | ✔ |
但是 MySQL 支持手动回滚,实际开发过程中可以自行手动对已提交的操作进行回滚操作,更加友好。
Das obige ist der detaillierte Inhalt vonVergleich von MySQL- und Redis-Transaktionen (Bild und Text). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!