トランザクションは、MySQL などのリレーショナル データベースと NoSQL を区別する重要な側面であり、データの一貫性を確保するための重要な手段です。 この記事では、最初にトランザクションに関連する 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 はトランザクションが満たさなければならない条件であると言われるのではなく、トランザクションを測定する 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 ログの書き込みタイミングは比較的多様です: 四、隔离性 1. 定义 与原子性、持久性侧重于研究事务本身不同,隔离性研究的是不同事务之间的相互影响。隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。严格的隔离性,对应了事务隔离级别中的Serializable (可串行化),但实际应用中出于性能方面的考虑很少会使用可串行化。 隔离性追求的是并发情形下事务之间互不干扰。简单起见,我们仅考虑最简单的读操作和写操作(暂时不考虑带锁读等特殊操作),那么隔离性的探讨,主要可以分为两个方面: 2. 锁机制 首先来看两个事务的写操作之间的相互影响。隔离性要求同一时刻只能有一个事务对数据进行写操作,InnoDB通过锁机制来保证这一点。 锁机制的基本原理可以概括为:事务在修改数据之前,需要先获得相应的锁;获得锁之后,事务便可以修改数据;该事务操作期间,这部分数据是锁定的,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。 行锁与表锁 按照粒度,锁可以分为表锁、行锁以及其他位于二者之间的锁。表锁在操作数据时会锁定整张表,并发性能较差;行锁则只锁定需要操作的数据,并发性能好。但是由于加锁本身需要消耗资源(获得锁、检查锁、释放锁等都需要消耗资源),因此在锁定数据较多情况下使用表锁可以节省大量资源。MySQL中不同的存储引擎支持的锁是不一样的,例如MyIsam只支持表锁,而InnoDB同时支持表锁和行锁,且出于性能考虑,绝大多数情况下使用的都是行锁。 如何查看锁信息 有多种方法可以查看InnoDB中锁的情况,例如: 下面来看一个例子: 此时查看锁的情况: 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)。 5. MVCC は行ロックの一種で、レコード ロック (レコード ロック) ギャップ ロック (##) に相当します。 # Gap lock); 特徴は、レコードそのものをロックするだけでなく(レコードロックの機能)、さらに範囲をロックする(ギャップロック)ことです。 #### ##関数)######。 もちろん、ここで話しているのはロック解除された読み取りです。このときのネクストキーロックは実際にはロックされておらず、読み取られたデータにマークを追加するだけです (マークの内容にはデータのバージョン番号が含まれます)。便宜上、これをネクストキーロック機構と呼ぶことにします。前の例を使用して説明しましょう: トランザクション A が T2 ノードで初めて 0 要約すると、InnoDB によって実装された RR は、ロック メカニズム、データの非表示列、元に戻すログ、ネクスト キー ロックを通じてある程度の分離を実現しており、ほとんどのシナリオのニーズを満たすことができます。ただし、RR はファントム読み取りの問題を回避しますが、結局シリアル化可能ではないため、完全な分離を保証できないことに注意してください。以下に例を示します。 ##5. 一貫性 #1. 基本概念 データベースの整合性制約が破壊されず、トランザクション実行前後のデータ状態が正常であることを意味します。 データベースの整合性制約には、エンティティの整合性 (行の主キーが存在し、一意であるなど)、列の整合性 (フィールドのタイプ、サイズ、長さが満たさなければならないなど) が含まれますが、これらに限定されません。要件)、外部キー制約、およびユーザー定義の完全性(たとえば、2 つの口座の残高の合計は転送の前後で変更されない必要があります)。 2. 実装 6概要 以上がMySQLトランザクションのACID特性(詳細説明)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。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;
アトミック性、耐久性、分離性を確保します。これらの特性が保証できない場合、トランザクションの一貫性も保証できません
推奨学習: