ホームページ  >  記事  >  データベース  >  MySQLトランザクションのACID特性(詳細説明)

MySQLトランザクションのACID特性(詳細説明)

青灯夜游
青灯夜游転載
2019-11-23 15:37:443209ブラウズ

トランザクションは、MySQL などのリレーショナル データベースと NoSQL を区別する重要な側面であり、データの一貫性を確保するための重要な手段です。 この記事では、最初にトランザクションに関連する MySQL 基本概念を紹介し、次にトランザクションの ACID 特性を紹介し、その実装原則を分析します。

MySQLトランザクションのACID特性(詳細説明)

#1. 基本概念

トランザクションはデータベース プログラムへのアクセスと更新に使用されます。実行単位。トランザクションには 1 つ以上の SQL ステートメントが含まれ、すべて実行されるかまったく実行されないかのいずれかです。 MySQL はリレーショナル データベースとしてトランザクションをサポートしており、この記事は MySQL5.6 に基づいています。

まず、MySQL トランザクションの基本を確認してください。

1. 論理アーキテクチャとストレージ エンジン

画像ソース: https://blog.csdn .net/fuzhongmin05/article/details/70904190

上の図に示すように、MySQL サーバーの論理アーキテクチャは上から下に 3 つの層に分けることができます。

(1) 最初の層層:顧客端末接続処理、認可認証など

(2) 第 2 層: サーバー層。クエリ ステートメントの解析、最適化、キャッシュ、組み込み関数の実装、ストアド プロシージャなどを担当します。

(3) 3 番目のレイヤー: ストレージ エンジン。MySQL でのデータの保存と取得を担当します。

MySQLサーバー層はトランザクションを管理せず、トランザクションはストレージ エンジンによって実装されます。 トランザクションをサポートする MySQL のストレージ エンジンには、InnoDB、NDB Cluster などがあり、その中で InnoDB が最も広く使用されていますが、MyIsam、Memory などの他のストレージ エンジンはトランザクションをサポートしていません。

特に指定のない限り、次の記事で説明する内容は InnoDB に基づいています。

#2. コミットとロールバック#典型的な MySQL トランザクションは次のように動作します:

start transaction;
……  #一条或多条sql语句
commit;

Starttransaction はトランザクションの開始を識別し、commit はトランザクションをコミットし、実行結果をデータベースに書き込みます。 SQL ステートメントの実行に問題がある場合、ロールバックが呼び出され、正常に実行されたすべての SQL ステートメントがロールバックされます。もちろん、トランザクション内で rollback ステートメントを直接使用してロールバックすることもできます。

Autocommit

MySQL は、以下に示すように、デフォルトで自動コミット モードを使用します。

自動コミットこのモードでは、トランザクションが starttransaction によって明示的に開始されない場合、各 SQL ステートメントはコミット操作を実行するトランザクションとして扱われます。

次の方法で自動コミットをオフにできます。自動コミット パラメータは接続に固有であることに注意してください。1 つの接続でパラメータを変更しても、他の接続には影響しません。

自動コミットがオフになっている場合、コミットまたはロールバックが実行され、トランザクションが終了し、別のトランザクションが開始されるまで、すべての SQL ステートメントは 1 つのトランザクション内にあります。

特別な操作

MySQL にはいくつかの特別なコマンドがあります。これらのコマンドがトランザクション内で実行されると、コミットはトランザクションをただちにコミットするように強制されます。 DDL ステートメント (create table/drop table/alter/table)、lock tables ステートメントなど。

ただし、一般的に使用される select、insert、update、および delete コマンドは、トランザクションを強制的にコミットしません。

3. ACID の特性

ACID は、トランザクションの 4 つの特性の尺度です:

原子性、または不可分性)

    一貫性
  • 分離
  • 耐久性
  • によると、厳格な基準に従って、ACID特性を満たすトランザクションのみが、同時にトランザクションとみなされますが、主要なデータベース ベンダーの実装では、ACID を真に満たすトランザクションはほとんどありません。たとえば、MySQL の MySQL Cluster トランザクションは耐久性と分離を満たしていません。InnoDB のデフォルトのトランザクション分離レベルは反復読み取りであり、分離を満たしていません。Oracle のデフォルトのトランザクション分離レベルは READ COMMITTED であり、分離を満たしていません...
  • So

ACID はトランザクションが満たさなければならない条件であると言われるのではなく、トランザクションを測定する 4 つの側面であると言った方が適切です。 ACID の特性とその実装原理については、以下で詳しく紹介しますが、理解を容易にするため、紹介の順序は厳密には A-C-I-D ではありません。

#2. 原子性

1. 定義

原子の特性トランザクションは分割できない作業単位であり、操作が完了するかまったく行われないことを意味します。トランザクション内の SQL ステートメントの実行に失敗した場合、実行されたステートメントもロールバックする必要があり、データベースはトランザクション前の状態に戻ります。 。 州。

2. 実装原則: 元に戻すログ

アトミック性の原理を説明する前に、まず MySQL トランザクション ログについて説明します。 MySQL ログには、バイナリ ログ、エラー ログ、クエリ ログ、スロー クエリ ログなど、さまざまな種類があります。さらに、InnoDB ストレージ エンジンは、REDO ログ (REDO ログ) と UNDO ログ (ロールバック ログ) の 2 つのトランザクション ログも提供します。 )。 REDO ログはトランザクションの耐久性を確保するために使用され、UNDO ログはトランザクションの原子性と分離の基礎となります。

アンドゥログについて話しましょう。アトミック性を実現する鍵は、トランザクションがロールバックされたときに、正常に実行されたすべての SQL ステートメントを元に戻せることです。 InnoDBロールバックは、UNDO ログに依存することで実現されます: トランザクションがデータベースを変更すると、InnoDB は対応する UNDO ログを生成します ; トランザクションの実行が失敗するか、rollback が呼び出され、トランザクションがロールバックされる場合、アンドゥ ログ 内の情報を使用して、データを元の状態にロールバックできます。改造前でした。

undo ログは、SQL の実行に関連する情報を記録する論理ログです。ロールバックが発生すると、InnoDB は元に戻すログの内容に基づいて前の作業の逆を実行します。挿入ごとに、ロールバック中に削除が実行され、削除ごとに、ロールバック中に挿入が実行され、更新ごとに実行されます。の場合、ロールバック中に削除が実行され、ロールバック時にはデータを元に戻す逆更新が実行されます。

更新操作を例に挙げます。トランザクションが更新を実行すると、生成される元に戻すログには、変更された行の主キー (どの行が変更されたかを知るため)、どの列が変更されたのかが含まれます。変更された値と、変更前後のこれらの列の値やその他の情報を使用して、ロールバック時にデータを更新前の状態に戻すことができます。

3. 持続性

1. 定義

持続性セックスこれは、トランザクションがコミットされると、データベースに対する変更が永​​続的に行われる必要があることを意味します。後続の操作や障害が影響を与えることはありません。

2. 実装原則: REDO ログ

REDO ログと UNDO ログは両方とも InnoDB トランザクション ログに属します。まずはREDOログが存在する背景についてお話しましょう。

InnoDB は MySQL のストレージ エンジンであり、データはディスクに保存されますが、データの読み書きに毎回ディスク IO が必要になると効率が非常に低くなります。この目的のために、InnoDB はキャッシュ (バッファ プール) を提供します。バッファ プールにはディスク上のいくつかのデータ ページのマッピングが含まれており、データベースにアクセスするためのバッファとして機能します。データベースからデータを読み取るときは、最初にバッファ プール。バッファ プールがプールに存在しない場合は、ディスクから読み取られてバッファ プールに入れられます。データベースにデータを書き込む場合は、最初にバッファ プールに書き込まれ、変更されたデータがバッファ プールに書き込まれます。バッファ プール内のデータは定期的にディスクに更新されます (このプロセスは ダーティ フラッシュ と呼ばれます)。

バッファ プールを使用すると、データの読み取りと書き込みの効率が大幅に向上しますが、新たな問題も生じます。MySQL がダウンし、バッファ プール内の変更されたデータがディスクにフラッシュされていない場合、データ損失とトランザクションの耐久性は保証できません。

そこで、この問題を解決するために REDO ログが導入されました。データが変更されると、バッファー プール内のデータの変更に加えて、トランザクションがコミットされたときの操作も REDO ログに記録されます。 、 fsync インターフェースが呼び出され、REDO ログがディスクをフラッシュするために使用されます。 MySQL がダウンした場合、REDO ログ内のデータを読み取り、再起動時にデータベースを復元できます。 REDO ログは WAL (先行書き込みログ、先行書き込みログ) を使用し、すべての変更は最初にログに書き込まれ、次にバッファ プールに更新されるため、MySQL のダウンタイムによってデータが失われることがないため、耐久性が満たされます。要件。

トランザクションのコミット時に REDO ログもディスクにログを書き込む必要があるのに、バッファ プール内の変更されたデータを直接ディスクに書き込む (つまり、ダーティに書き込む) よりも高速なのはなぜでしょうか。 ?理由は主に 2 つあります。

(1) ダーティ クリーニングはランダム IO です。毎回変更されるデータの場所はランダムですが、REDO ログの書き込みは追加操作であり、シーケンシャル IO に属します。

(2) ダーティ クリーニングはデータ ページ (ページ) に基づいています。MySQL のデフォルトのページ サイズは 16KB です。ページ上の小さな変更にはページ全体を書き込む必要があり、REDO ログには内容のみが含まれます。書き込み部分では、無効な IO が大幅に削減されます。

3. REDO ログと binlog

MySQL には、書き込み操作を記録できる binlog (バイナリ ログ) もあることはわかっています。

(1) 異なる機能: REDO ログは、MySQL のダウンタイムが永続性に影響を与えないようにクラッシュ リカバリに使用され、binlog はポイントインに使用されます。 -time Recovery は、サーバーが時点に基づいてデータを回復できることを保証します。さらに、binlog はマスター/スレーブ レプリケーションにも使用されます。

(2) さまざまなレベル: REDO ログは InnoDB ストレージ エンジンによって実装され、binlog は MySQL サーバー層によって実装されます (記事前半の MySQL 論理アーキテクチャの概要を参照してください)。 InnoDB と他のストレージを同時に使用できます。

(3) 内容が異なります: REDO ログは物理ログであり、内容はディスク ページに基づいています。binlog の内容はバイナリです。binlog_format パラメータによっては、SQL ステートメントに基づく場合があります。 、データ自体、またはその 2 つの混合。

(4) 異なる書き込みタイミング: binlog はトランザクションのコミット時に書き込まれますが、REDO ログの書き込みタイミングは比較的多様です:

  • 前面曾提到:当事务提交时会调用fsync对redo log进行刷盘;这是默认情况下的策略,修改innodb_flush_log_at_trx_commit参数可以改变该策略,但事务的持久性将无法保证。
  • 除了事务提交时,还有其他刷盘时机:如master thread每秒刷盘一次redo log等,这样的好处是不一定要等到commit时刷盘,commit速度大大加快。

四、隔离性

1. 定义

与原子性、持久性侧重于研究事务本身不同,隔离性研究的是不同事务之间的相互影响。隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。严格的隔离性,对应了事务隔离级别中的Serializable (可串行化),但实际应用中出于性能方面的考虑很少会使用可串行化。

 

隔离性追求的是并发情形下事务之间互不干扰。简单起见,我们仅考虑最简单的读操作和写操作(暂时不考虑带锁读等特殊操作),那么隔离性的探讨,主要可以分为两个方面:

  • (一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性
  • (一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性

2. 锁机制

首先来看两个事务的写操作之间的相互影响。隔离性要求同一时刻只能有一个事务对数据进行写操作,InnoDB通过锁机制来保证这一点。

锁机制的基本原理可以概括为:事务在修改数据之前,需要先获得相应的锁;获得锁之后,事务便可以修改数据;该事务操作期间,这部分数据是锁定的,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。

行锁与表锁

按照粒度,锁可以分为表锁、行锁以及其他位于二者之间的锁。表锁在操作数据时会锁定整张表,并发性能较差;行锁则只锁定需要操作的数据,并发性能好。但是由于加锁本身需要消耗资源(获得锁、检查锁、释放锁等都需要消耗资源),因此在锁定数据较多情况下使用表锁可以节省大量资源。MySQL中不同的存储引擎支持的锁是不一样的,例如MyIsam只支持表锁,而InnoDB同时支持表锁和行锁,且出于性能考虑,绝大多数情况下使用的都是行锁。

如何查看锁信息

有多种方法可以查看InnoDB中锁的情况,例如:


select * from information_schema.innodb_locks; #锁的概况
show engine innodb status; #InnoDB整体状态,其中包括锁的情况

下面来看一个例子:


#在事务A中执行:
start transaction;
update account SET balance = 1000 where id = 1;
#在事务B中执行:
start transaction;
update account SET balance = 2000 where id = 1;

此时查看锁的情况:

show engine innodb status查看锁相关的部分:

通过上述命令可以查看事务24052和24053占用锁的情况;其中lock_type为RECORD,代表锁为行锁(记录锁);lock_mode为X,代表排它锁(写锁)。

除了排它锁(写锁)之外,MySQL中还有共享锁(读锁)的概念。由于本文重点是MySQL事务的实现原理,因此对锁的介绍到此为止,后续会专门写文章分析MySQL中不同锁的区别、使用场景等,欢迎关注。

介绍完写操作之间的相互影响,下面讨论写操作对读操作的影响。

3. 脏读、不可重复读和幻读

首先来看并发情况下,读操作可能存在的三类问题:

(1)脏读:当前事务(A)中可以读到其他事务(B)未提交的数据(脏数据),这种现象是脏读。举例如下(以账户余额表为例):

(2)不可重复读:在事务A中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。举例如下:

(3)幻读:在事务A中按照某个条件先后两次查询数据库,两次查询结果的条数不同,这种现象称为幻读。不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了。举例如下:

4. トランザクション分離レベル

SQL 標準では 4 つの分離レベルが定義されており、各分離レベルで上記の問題が存在するかどうかが規定されています。一般に、分離レベルが低いほど、システムのオーバーヘッドが低くなり、サポートできる同時実行性は高くなりますが、分離は悪化します。分離レベルと読み取りの問題の関係は次のとおりです。

実際のアプリケーションでは、read uncommitted は同時実行中に多くの問題を引き起こし、パフォーマンスは比較的低くなります。その他の分離レベルの改善には制限があるため、あまり一般的には使用されません。 Serializableトランザクションを強制的にシリアル化すると、同時実行効率が非常に低くなります。これは、データの一貫性要件が非常に高く、同時実行性が許容されない場合にのみ使用できるため、ほとんど使用されません。したがって、ほとんどのデータベース システムでは、デフォルトの分離レベルは Read Committed (Oracle などの ) または Repeatable Read (以下 # # と呼ばれます) です。 #RR)

次の 2 つのコマンドを使用して、グローバル分離レベルとこのセッションの分離レベルを表示できます:

InnoDB デフォルトの分離レベルは RR ですが、RR については後ほど説明します。 SQL 標準では、RR はファントム リードの問題を回避できませんが、InnoDB によって実装された RR はファントム リードの問題を回避することに注意してください。

5. MVCC

RR は、MVCC を使用して、ダーティ リード、反復不能リード、ファントム リードなどの問題を解決します。正式名は Multi-Version Concurrency Control で、複数バージョンの同時実行制御プロトコルです。次の例は、MVCC の特性をよく反映しています: 同時に、異なるトランザクションによって読み取られるデータは異なる場合があります (つまり、複数のバージョン) - 時間 T5 では、トランザクション A とトランザクション C は異なるバージョンのデータを読み取ることができます。

#MVCC の最大の利点は、読み取りがロックされないため、読み取りと書き込みの間に競合がなく、同時実行パフォーマンスが優れていることです。 InnoDB は MVCC を実装しており、主にデータの非表示列 (マーク ビットとも呼ばれます) と Undo ログに依存して、複数のバージョンのデータが共存できます。データの非表示列には、データ行のバージョン番号、削除時刻、アンドゥ ログへのポインタなどが含まれます。データを読み取るときに、MySQL は非表示列を使用して、ロールバックが必要かどうかを判断し、ロールバックには undo ログが必要であるため、MVCC が実装され、非表示列の詳細な形式は拡張されなくなりました。

以下の内容は、上記のいくつかの問題と併せて個別に説明されています。

(1) ダーティリード

トランザクション A が T3 タイムノードで zhangsan の残高を読み取ると、データが他のユーザーによって変更されていることがわかります。トランザクション、ステータスは未コミットです。このとき、トランザクションAが最新データを読み込んだ後、データのアンドゥログを基にロールバック操作を行い、トランザクションBが変更される前のデータを取得することでダーティリードを回避します。

(2) Non-repeatable read

トランザクション A が T2 ノードで初めてデータを読み取るとき、データのバージョン番号 (データバージョン番号は行単位で記録されます)、バージョン番号が 1 であると仮定すると、トランザクション B がコミットすると、この行に記録されるバージョン番号は増加します(バージョン番号が 2 と仮定すると)、T5 でトランザクション A が再度データを読み取ると、データ(2)のバージョン番号は、初回読み込み時に記録したバージョン番号(1)よりも大きいため、アンドゥログに基づいてロールバック操作を行い、バージョン番号が1のときのデータを取得し、これにより、繰り返し可能な読み取りが実現します。

(3) ファントム読み取り

InnoDB によって実装された RR は、ネクスト キー ロック メカニズムを通じてファントム読み取り現象を回避します。

#next-key lock

は行ロックの一種で、レコード ロック (レコード ロック) ギャップ ロック (##) に相当します。 # Gap lock); 特徴は、レコードそのものをロックするだけでなく(レコードロックの機能、さらに範囲をロックする(ギャップロック)ことです。 #### ##関数)######。 もちろん、ここで話しているのはロック解除された読み取りです。このときのネクストキーロックは実際にはロックされておらず、読み取られたデータにマークを追加するだけです (マークの内容にはデータのバージョン番号が含まれます)。便宜上、これをネクストキーロック機構と呼ぶことにします。前の例を使用して説明しましょう: トランザクション A が T2 ノードで初めて 0

#6. 概要

要約すると、InnoDB によって実装された RR は、ロック メカニズム、データの非表示列、元に戻すログ、ネクスト キー ロックを通じてある程度の分離を実現しており、ほとんどのシナリオのニーズを満たすことができます。ただし、RR はファントム読み取りの問題を回避しますが、結局シリアル化可能ではないため、完全な分離を保証できないことに注意してください。以下に例を示します。

##5. 一貫性

#1. 基本概念

一貫性とは、トランザクション実行終了後、

データベースの整合性制約が破壊されず、トランザクション実行前後のデータ状態が正常であることを意味します。 データベースの整合性制約には、エンティティの整合性 (行の主キーが存在し、一意であるなど)、列の整合性 (フィールドのタイプ、サイズ、長さが満たさなければならないなど) が含まれますが、これらに限定されません。要件)、外部キー制約、およびユーザー定義の完全性(たとえば、2 つの口座の残高の合計は転送の前後で変更されない必要があります)。

2. 実装

一貫性はトランザクションによって追求される最終的な目標であると言えます: 前述した原子性、耐久性、分離性、すべてはデータベース状態の一貫性を確保するためです。さらに、整合性の実装には、データベース レベルでの保証に加えて、アプリケーション レベルでの保証も必要です。

一貫性を達成するための対策には次のものが含まれます:

    アトミック性、耐久性、分離性を確保します。これらの特性が保証できない場合、トランザクションの一貫性も保証できません
  • データベース自体たとえば、整数列に文字列値を挿入できないこと、文字列の長さが列制限を超えることができないことなどの保証を提供します。
  • 保証は、アプリケーション レベルで提供されます。たとえば、送金操作は送金者の残高を差し引くだけで、受取人の残高を増やすことはできません。データベースがどれほど完璧に実装されていても、状態が一貫していることは保証できません

6概要

ACID の特性とその実装原則を要約すると、次のようになります:

  • 原子性: ステートメントは完全に実行されるか、まったく実行されないかのどちらかです。 . これはトランザクションの中核的な特性です。トランザクション自体はアトミック性によって定義されます。;実装は主に undo ログに基づいています

  • 永続性: データが次の理由で失われないことを保証します。トランザクション送信後のダウンタイムやその他の理由。実装は主に REDO ログに基づいています。

  • 分離: トランザクションの実行が他のトランザクションの影響をできるだけ受けないようにします。InnoDB のデフォルトの分離レベルは RR です。 RR の実装は主に、ロック メカニズム、データの非表示列、元に戻すログ、ネクスト キー ロック メカニズムに基づいています
  • 一貫性: トランザクションによって追求される最終目標。一貫性の実現には、次のような保護が必要です。データベース レベルとアプリケーション レベルの両方。

推奨学習:

MySQL チュートリアル

以上がMySQLトランザクションのACID特性(詳細説明)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。