Heim  >  Artikel  >  Datenbank  >  Detaillierte Analyse von MySQL-Transaktionen

Detaillierte Analyse von MySQL-Transaktionen

WBOY
WBOYnach vorne
2022-03-10 17:59:111590Durchsuche

Dieser Artikel vermittelt Ihnen relevantes Wissen über MySQL. Er stellt hauptsächlich die Transaktions-ACID-Eigenschaften von MySQL und die Syntax des MySQL-Transaktionssteuerungsprozesses vor und stellt ungewöhnliche Situationen vor, die bei der gleichzeitigen Transaktionsverarbeitung auftreten können, z. B. Dirty Reads und Phantom Reads , nicht wiederholbare Lesevorgänge usw. Abschließend stelle ich die Transaktionsisolationsstufe vor und hoffe, dass sie für alle hilfreich ist.

Detaillierte Analyse von MySQL-Transaktionen

Empfohlenes Lernen: MySQL-Lernprogramm

In tatsächlichen Geschäftsszenarien ist es wichtig, eine Reihe logisch zusammenhängender Vorgänge nacheinander auszuführen Es ist sehr wahrscheinlich, dass es zu Datenverwirrungen kommt.

Stellen Sie sich die Szene vor, in der wir an einem Geldautomaten Geld abheben. Wenn wir tausend Yuan abheben, spuckt der Geldautomat nach Abschluss der Zählung tausend Yuan auf einmal aus, anstatt jedes Mal hundert Yuan auszuspucken Stellen Sie sicher, dass der Vorgang vollständig ist. Der Vollständigkeit halber wird entweder tausend Yuan vollständig abgehoben und der Restbetrag abgezogen, oder es wird kein Cent abgehoben und der Restbetrag bleibt unverändert, ohne dass es zu Dateninkonsistenzen aufgrund eines Maschinenausfalls in der Mitte kommt. Eine solche vollständige Operation wird als Transaktion bezeichnet. Alle Operationen in einer Transaktion werden entweder erfolgreich oder überhaupt nicht ausgeführt. 事务 transaction,一个事务中的所有操作要么全部成功执行,要么完全不执行。

本文将会介绍 MySQL 的事务 ACID 特性和 MySQL 事务控制流程的语法,并介绍事务并发处理中可能出现的异常情况,比如脏读、幻读、不可重复读等等,最后介绍事务隔离级别。

关于实现事务隔离性的锁和 MVCC,将会在之后的文章进行介绍。

ACID 特性

事务处理是一种对必须整批执行的 MySQL 操作的管理机制,在事务过程中,除非整批操作全部正确执行,否则中间的任何一个操作出错,都会回滚 (Rollback) 到最初的安全状态以确保不会对系统数据造成错误的改动。

之前的文章中我们提到过,MySQL 5.5 之后,默认的存储引擎从 MyISAM 替换成了 InnoDB,这其中的一个重要原因就是因为 InnoDB 支持事务,我们用 SHOW ENGINES 来看一下 MySQL 中对各种存储引擎的描述。
Detaillierte Analyse von MySQL-Transaktionen
事务最重要的四个特性通常被称为 ACID 特性
A - Atomicity 原子性: 一个事务是一个不可分割的最小单位,事务中的所有操作要么全部成功,要么全部失败,没有中间状态。原子性主要是通过事务日志中的回滚日志(undo log)来实现的,当事务对数据库进行修改时,InnoDB 会根据操作生成相反操作的 undo log,比如说对 insert 操作,会生成 delete 记录,如果事务执行失败或者调用了 rollback,就会根据 undo log 的内容恢复到执行之前的状态。

C - Consistency 一致性: 事务执行之前和执行之后数据都是合法的一致性状态,即使发生了异常,也不会因为异常引而破坏数据库的完整性约束,比如唯一性约束等。

I - Isolation 隔离性: 每个事务是彼此独立的,不会受到其他事务的执行影响,事务在提交之前对其他事务不可见。隔离性通过事务的隔离级别来定义,并用锁机制来保证写操作的隔离性,用 MVCC 来保证读操作的隔离性,将在下文详细介绍。

D - Durability 持久性: 事务提交之后对数据的修改是持久性的,即使数据库宕机也不会丢失,通过事务日志中的重做日志(redo log)来保证。事务修改之前,会先把变更信息预写到 redo log 中,如果数据库宕机,恢复后会读取 redo log 中的记录来恢复数据。

事务控制语法

MySQL 事务控制有几个重要节点,分别是事务的开启,提交,回滚和保存点。

开启事务代表事务开始执行,语句为 START TRANSACTION 或者 BEGIN,提交事务代表将事务中的所有更新都写到磁盘的物理数据库,事务正常执行结束,语句为 COMMIT,如果发生异常需要回滚,语句为 ROLLBACK。要注意的是,一旦事务已经提交,就不能回滚了,因此,在代码执行过程中捕获到异常的时候需要直接执行 rollback 而不是 commit。

比如 A 向 B 转账 100 元的事务:

// 正常执行,提交
BEGIN; # 开启事务
UPDATE account_balance SET balance = balance - 100.00 WHERE account_name = 'A';
UPDATE account_balance SET balance = balance + 100.00 WHERE account_name = 'B';
COMMIT; # 提交事务

// 发生异常,回滚
BEGIN; # 开启事务
UPDATE account_balance SET balance = balance - 100.00 WHERE account_name = 'A';
UPDATE account_balance SET balance = balance + 100.00 WHERE account_name = 'B';
ROLLBACK; # 事务回滚

在复杂场景中,有时我们不需要全盘回滚整个操作,而是分批执行,回滚到某个节点就好了,相当于是在一个大事务下嵌套了若干个子事务,在 MySQL 中可以使用保留点 SAVEPOINT

In diesem Artikel werden die Transaktions-ACID-Funktion von MySQL und die Syntax des MySQL-Transaktionssteuerungsprozesses vorgestellt und mögliche Ausnahmen bei der gleichzeitigen Transaktionsverarbeitung vorgestellt, wie z. B. Dirty Reads, Phantom Reads und nicht wiederholbare Lesevorgänge usw. und schließlich die Transaktionsisolationsstufe einführen. 🎜🎜Über Sperren und MVCC zur Erzielung der Transaktionsisolation werden wir sie in einem späteren Artikel vorstellen. 🎜

ACID-Funktionen

🎜Die Transaktionsverarbeitung ist ein Verwaltungsmechanismus für MySQL-Vorgänge, der während des Transaktionsprozesses in einem Stapel ausgeführt werden muss, es sei denn, der gesamte Stapel von Vorgängen wird korrekt ausgeführt, andernfalls wird jeder Vorgang in der Mitte ausgeführt Rollback schlägt fehl, um sicherzustellen, dass keine fehlerhaften Änderungen an den Systemdaten vorgenommen werden. 🎜🎜Wir haben im vorherigen Artikel erwähnt, dass die Standardspeicher-Engine nach MySQL 5.5 von MyISAM auf InnoDB umgestellt wurde. Einer der wichtigen Gründe dafür ist, dass InnoDB Transaktionen unterstützt Schauen Sie sich die Beschreibungen verschiedener Speicher-Engines in MySQL an.
Bildbeschreibung hier einfügen
Die Die vier wichtigsten Merkmale von Transaktionen werden üblicherweise als ACID-Merkmale
A – Atomarität bezeichnet: Eine Transaktion ist eine unteilbare kleinste Einheit. Es gibt entweder Erfolg oder Misserfolg kein Zwischenzustand. Atomarität wird hauptsächlich durch Rollback-Protokoll (Rückgängig-Protokoll) im Transaktionsprotokoll erreicht. Wenn eine Transaktion die Datenbank ändert, generiert InnoDB ein Rückgängig-Protokoll des entgegengesetzten Vorgangs, z. B. des Einfügevorgangs Wenn die Transaktionsausführung fehlschlägt oder ein Rollback aufgerufen wird, wird der Zustand vor der Ausführung basierend auf dem Inhalt des Rückgängig-Protokolls wiederhergestellt. 🎜🎜C – Konsistenz: Die Daten befinden sich vor und nach der Ausführung der Transaktion in einem rechtlichen Konsistenzzustand. Selbst wenn eine Ausnahme auftritt, werden die Integritätsbeschränkungen der Datenbank nicht durch Ausnahmen verletzt, z als Eindeutigkeitsbeschränkungen usw. 🎜🎜I – Isolation Isolation: Jede Transaktion ist unabhängig voneinander und wird durch die Ausführung anderer Transaktionen nicht beeinflusst. Eine Transaktion ist für andere Transaktionen nicht sichtbar, bevor sie festgeschrieben wird. Die Isolation wird durch die Isolationsstufe der Transaktion definiert, und der Sperrmechanismus wird verwendet, um die Isolation von Schreibvorgängen sicherzustellen, und MVCC wird verwendet, um die Isolation von Lesevorgängen sicherzustellen, was im Folgenden ausführlich vorgestellt wird. 🎜🎜D - Dauerhaftigkeit: Änderungen an den Daten nach der Übermittlung der Transaktion sind dauerhaft und gehen auch dann nicht verloren, wenn die Datenbank ausfällt. Durch das -Redo-Log im Transaktionsprotokoll (Redo-Log). ) um sicherzustellen. Bevor die Transaktion geändert wird, werden die Änderungsinformationen vorab in das Redo-Log geschrieben. Wenn die Datenbank ausfällt, werden die Datensätze im Redo-Log nach der Wiederherstellung gelesen, um die Daten wiederherzustellen. 🎜

Syntax der Transaktionssteuerung

🎜Die MySQL-Transaktionssteuerung verfügt über mehrere wichtige Knoten, nämlich Transaktionsstart, Festschreibung, Rollback und Speicherpunkt. 🎜🎜Das Öffnen einer Transaktion bedeutet, dass die Transaktion mit der Ausführung beginnt. Die Anweisung lautet START TRANSACTION oder BEGIN. Das Senden der Transaktion bedeutet, dass alle Aktualisierungen in der Transaktion in die physische Datenbank geschrieben werden Die Anweisung lautet am Ende COMMIT. Wenn eine Ausnahme auftritt und ein Rollback erforderlich ist, lautet die Anweisung ROLLBACK. Es ist zu beachten, dass eine einmal festgeschriebene Transaktion nicht mehr zurückgesetzt werden kann. Wenn daher während der Codeausführung eine Ausnahme auftritt, muss das Rollback direkt anstelle des Festschreibens ausgeführt werden. 🎜🎜Zum Beispiel überweist A 100 Yuan an B: 🎜
BEGIN;
insert into user_tbl (id) values (1) ;
insert into user_tbl (id) values (2) ;
ROLLBACK;   # 1,2 都没有写入
BEGIN;
insert into user_tbl (id) values (1) ;
SAVEPOINT s1;
insert into user_tbl (id) values (2) ;
ROLLBACK TO s1;   # 回滚到保留点 s1, 因此 1 成功写入,2 被回滚, 最终结果为 1
RELEASE SAVEPOINT s1; # 释放保留点
🎜In komplexen Szenarien müssen wir manchmal nicht den gesamten Vorgang zurücksetzen, sondern ihn einfach stapelweise auf einen bestimmten Knoten zurücksetzen, was äquivalent ist a Mehrere Untertransaktionen sind unter einer großen Transaktion verschachtelt, was über den Speicherpunkt SAVEPOINT in MySQL implementiert werden kann. 🎜
BEGIN;
insert into user_tbl (id) values (1) ;
insert into user_tbl (id) values (2) ;
ROLLBACK;   # 1,2 都没有写入
BEGIN;
insert into user_tbl (id) values (1) ;
SAVEPOINT s1;
insert into user_tbl (id) values (2) ;
ROLLBACK TO s1;   # 回滚到保留点 s1, 因此 1 成功写入,2 被回滚, 最终结果为 1
RELEASE SAVEPOINT s1; # 释放保留点

顺便提一下,事务有隐式事务(自动提交)和显示事务(必须手动提交)两种,MySQL 默认为隐式事务,会进行自动提交,通过 autocommit 参数来控制。

# 查看变量
SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
# 开启自动提交(默认)
SET autocommit = 1;
# 关闭自动提交
SET autocommit = 0;

在自动提交状态下,如果没有显示的开启事务,那每一条语句都是一个事务,系统会自动对每一条 sql 执行 commit 操作。使用 BEGIN 或 START TRANSACTION 开启一个事务之后,自动提交将保持禁用状态,直到使用 COMMIT 或 ROLLBACK 结束事务之后,自动提交模式会恢复到之前的状态。

关于事务还有另一个参数 completion_type,默认取值为 0 (NO_CHAIN)

# 查看变量
SHOW VARIABLES LIKE 'completion_type';
+-----------------+----------+
| Variable_name   |   Value  |
+-----------------+----------+
| completion_type | NO_CHAIN |
+-----------------+----------+

completion_type = 0: 默认值,执行 commit 后不会自动开启新的事务。
completion_type = 1: 执行 commit 时,相当于执行 COMMIT AND CHAIN,自动开启一个相同隔离级别的事务。
completion_type = 2: 执行 commit 时,相当于执行 COMMIT AND RELEASE,提交事务后自动断开服务器连接。

事务并发异常

在实际产线环境下,可能会存在大规模并发请求的情况,如果没有妥善的设置事务的隔离级别,就可能导致一些异常情况的出现,最常见的几种异常为脏读(Dirty Read)幻读(Phantom Read)不可重复读(Unrepeatable Read)

脏读

脏读指一个事务访问到了另一个事务未提交的数据,如下过程:

  1. 假设 a 的值为 1,事务 2 把 a 改为 2,此时事务还未提交
  2. 在这个时候,事务 1 读取 a,读得 a 的值为 2,事务 1 读取完成
  3. 结果事务 2 回滚了对 a 的修改(或者是未 commit),于是 a 的值变回 1
  4. 这就导致事实上 a 的值为 1,但是事务 1 取得的结果为 2,所以事务 1 读到了脏数据,发生脏读
    Detaillierte Analyse von MySQL-Transaktionen

不可重复读

不可重复读指一个事务多次读取同一数据的过程中,数据值 内容 发生了改变,导致没有办法读到相同的值,描述的是针对同一条数据 update/delete 的现象,如下过程:

  1. 事务 1 读取 a,此时 a = 1
  2. 此时事务 2 将 a 修改为 2,并成功提交,改动生效
  3. 事务 1 又一次读取 a,此时 a = 2
  4. 事务 1 在同一个事务里面两次读取同一个值,数据值内容却发生了改变,发生不可重复读
    Detaillierte Analyse von MySQL-Transaktionen

幻读

幻读指一个事务多次读取同一数据的过程中,全局数据(如数据行数)发生了改变,仿佛产生了幻觉,描述的是针对全表 insert/delete 的现象,如下过程:

  1. 事务 1 第一次读取数量,得到 10 条数据
  2. 此时事务 2 插入了一条数据并成功提交,改动生效,数据变成 11 条
  3. 事务 1 再次读取数量,得到 11 条数据,对事务 1 而言莫名其妙的多了一条,好像产生幻觉了一样,发生幻读
    Detaillierte Analyse von MySQL-Transaktionen

或者是另一种场景,比如对于有唯一性约束的字段(如 id),发生如下过程:

  1. 事务 1 要插入 id = 5 的记录,先查询数据库,发现不存在 id = 5 的数据,可以正常插入。
  2. 这时候事务 2 插入了一条数据 id = 5。
  3. 事务 1 插入 id = 5 时,发现报错唯一性冲突,对事务 1 来讲就好像见了鬼了,我刚刚明明检查过没有,怎么这时候又有了。
    Detaillierte Analyse von MySQL-Transaktionen

事务隔离级别

串行化的事务处理方式当然是最安全的,但是串行无法满足数据库高并发访问的需求,作为妥协,有时不得不降低数据库的隔离标准来换取事务的并发能力,通过在可控的范围内牺牲正确性来换取效率的提升,这种权衡通过事务的隔离级别来实现。

数据库有 4 种事务隔离级别,由低到高依次为 读未提交 Read Uncommitted读已提交 Read Committed可重复读 Repeatable Read串行化 Serializable

  1. 读未提交 Read Uncommitted
    允许读取未提交的内容,这种级别下的查询不会加锁,因此脏读、不可重复读、幻读都有可能发生。

  2. 读已提交 Read Committed
    只允许读取已提交的内容,这种级别下的查询不会发生脏读,因为脏数据属于未提交的数据,所以不会被读取,但是依然有可能发生不可重复读和幻读。

  3. 可重复读 Repeatable Read (MySQL 的默认隔离级别)
    使用行级锁来保证一个事务在相同查询条件下两次查询得到的数据结果一致,可以避免脏读和不可重复读,但是没有办法避免幻读。

    需要特殊注意的是,Innodb 在 Repeatable Read 下通过 MVCC 提供了稳定的视图,因此 Innodb 的 RR 隔离级别下是不会出现上述幻读异常中的第一个场景的,但第二个场景还是会出现。

  4. 串行化 Serializable
    使用表级锁来保证所有事务的串行化,可以防止所有的异常情况,但是牺牲了系统的并发性。

查看隔离级别的命令为

SHOW VARIABLES LIKE 'transaction_isolation';
# 或者
SELECT @@global.tx_isolation, @@tx_isolation;

第二种方式可以查看全局和当前会话的隔离级别。
Detaillierte Analyse von MySQL-Transaktionen
设置隔离级别的命令为

# 将当前会话的隔离级别设为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 
# 将全局的隔离级别设为读未提交
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

结语

本文简单介绍了 MySQL 事务的语法和 ACID 特性,以及事务并发处理中可能出现的异常情况和为了防止这些异常而设计的事务隔离级别。有兴趣的朋友可以尝试在两个不同的 MySQL 客户端来模拟四种隔离级别下三种异常的发生情况,在之后的文章中,会继续深入探讨 MySQL 是如何实现隔离级别的。

推荐学习:mysql学习视频教程

Das obige ist der detaillierte Inhalt vonDetaillierte Analyse von MySQL-Transaktionen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:csdn.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen