第三章:
事務
トランザクションは、DBMS の操作の基本的な実行単位です。トランザクション自体は、一連の DML ステートメント INSERT、DELETE、および UPDATE で構成される単一の論理作業単位を構成する、限定された一連のデータベース操作です。
リレーショナル データベースでは、トランザクションはステートメント、一連の SQL ステートメント、またはプログラム全体の場合があります。
トランザクションとプログラムの違い: プログラムには複数のトランザクションが含まれます。
暗黙的なトランザクションと自動コミットSQL ステートメント
- DDL 句:ALTER、CREATE、RENAME、DROP、TRUNCATE
- ユーザー権限管理操作: CREATE USER、GRANT、REVOKE、SET PASSWORD
- 管理ステートメント: ANALYZE TABLE、CHECK INDEX、REPAIR TABLE、LOAD INDEX INTO CACHE
注文:
- set autocommit=0 : トランザクションの自動コミットをオフにします
- begin : トランザクションを開始します
- commit : トランザクションをコミットします
- rollback : トランザクションのロールバック
- トランザクションの開始: 開いているトランザクションを表示します
InnoDB ストレージ エンジンは、デフォルトでトランザクションを自動的にコミットし、暗黙的に各行を 1 回コミットします。これは非常に時間がかかり、多数の挿入が発生したときにエラーが発生してもロールバックできません。
↑このケースに合わせて最適化し、トランザクションを明示的に開始して送信し、ループ本体をトランザクションに入れて循環送信を回避します。
ACIDトランザクションの4つの主要な特徴
- アトミック性: トランザクション内の操作は完了するか完了しないかのいずれかであり、分割できません。アトミック性はトランザクション概念の本質であり、基本的な要件です。
- 一貫性: トランザクションの実行結果によって、データベースはある一貫した状態から別の一貫した状態に変化する必要があります。
- 分離: 同時に実行されるトランザクションは相互に干渉できません。
- 耐久性: トランザクションがコミットされると、データベースへの更新はその後の操作や障害の影響を受けなくなります。
トランザクション分離レベル
トランザクションの読み取りおよび書き込みの問題
MySQL は複数のスレッドによって同時にアクセスされるデータベースであるため、複数のユーザー (複数のトランザクション) が同じデータベース リソースに同時にアクセスする、つまりコンカレント環境では、次のような不確実な状況が発生する可能性があります。
- ダーティ リード: トランザクションがデータ行を読み取り、別のトランザクションがこの行のデータを更新しましたが、時間内にコミットされませんでした。 **たとえば、トランザクション A はトランザクション B によって更新されたデータを読み取り、その後トランザクション B がその理由は、ロールバック操作が実行され、トランザクション A によって読み取られたデータがダーティ データであるためです。**この状況は非常に危険であり、すべての操作がロールバックされる可能性があります。
- 非反復読み取り: 非反復読み取りとは、1 つのトランザクションを変更および送信すると、別のトランザクションの同じ範囲にある 2 つの同一のクエリの戻り結果が異なることを意味します。たとえば、トランザクション A は同じデータを複数回読み取る必要があり、トランザクション A が終了する前にトランザクション B がそのデータにアクセスして変更すると、トランザクション A によって 2 回読み取られたデータに不整合が生じる可能性があるため、これは非反復読み取りと呼ばれます。
- ファントム読み取り: ファントム読み取りとは、あるスレッドのトランザクションが、別のスレッドで送信された INSERT データを読み取ることを意味します。たとえば、ユーザー A は、データベース内のすべての生徒の成績を特定のスコアから ABCDE の成績に変更しますが、ユーザー B はこの時点で特定のスコアのレコードを挿入します。変更後、ユーザー A は、まだ変更されていないレコードが存在することに気づきます。この状況はファントム リーディングまたはファントム リーディングです。
MySQL のトランザクション分離レベル
特性 | 説明する |
---|---|
ReadUncommitted コミットされていない読み取り | トランザクションが他のトランザクションのコミットされていない結果を読み取ることを許可する (つまり、ダーティ リードを許可する) ことは、最も低く、最も危険なトランザクション分離レベルであり、このレベルが実際のアプリケーションで使用されることはほとんどありません。 |
コミットされた読み取り コミットされた読み取り | トランザクションは、他のトランザクションのコミットされた結果のみを読み取ることができます。この分離レベルでは、ダーティ リードは回避できますが、繰り返しの読み取りとファントム リードは回避できません。 |
反復可能読み取り反復可能読み取り (デフォルト) | このレベルでは、同じトランザクションの複数のインスタンスが同時にデータを読み取るときに、同じデータ行を確実に読み取ることができます。このレベルでは、ダーティ リードと反復不可能な読み取りの問題は回避できますが、ファントム リードの問題は回避できません。これは MySQL のデフォルトの分離レベルです。 |
シリアライズ可能はシリアライズ可能 | トランザクションが互いに競合しないようにソートすることが必須であり、これによりファントム読み取りの問題が解決されます。実際、この方法では各読み取りデータ行に共有ロックが追加されますが、このレベルでは大量のタイムアウトやロック競合が発生する可能性があるため、実際のアプリケーションではほとんど使用されず、トランザクションでは最も高い分離レベルとなります。 |
注文:
- SELECT @@tx_isolation; 現在のセッションの分離レベルを表示します (5.7)
- SELECT @@transaction_isolation; 現在のセッションの分離レベルを表示します (8.0)
- SET SESSION TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}: 現在のセッションの分離レベルを変更します。
ロック機構
ロック メカニズムは主に、ユーザーがデータに正常にアクセスできるようにし、データの一貫性を確保することを目的としています。ロック メカニズムは、巨視的には高い同時実行性を実現する最も簡単な方法ですが、微視的に見ると、ロック メカニズムは実際には読み取りと書き込みのシリアル化です。
ロックの粒度
ロックの粒度は、ロックの範囲を指します。InnoDB ストレージ エンジンはテーブル レベルのロックと行レベルのロックをサポートし、MyISAM ストレージ エンジンはテーブル レベルのロックをサポートします。
暗黙的ロックと明示的ロック
MySQL による自動ロックは暗黙的ロックと呼ばれ、データベース開発者による手動ロックは明示的ロックと呼ばれます。
MySQL 読み取り/書き込みロック
読み取りロック: 読み取りロックは共有ロックとも呼ばれ、他のユーザーが同時にデータを「読み取る」ことはできますが、他のユーザーが同時にデータを「書き込む」ことはできません。
書き込みロック:書き込みロックは、排他ロックまたは排他ロックとも呼ばれます。書き込みロックでは、他のユーザーが同時にデータを「読み取る」ことも、他のユーザーが同時にデータを「書き込む」こともできません。
InnoDB ロック タイプ
テーブルレベルのロック: テーブルレベルのロックは、テーブル全体がクライアントによってロックされることを意味します。テーブルレベルのロックは、読み取りロック、書き込みロック、およびインテント ロックに分類されます。
- コマンド:LOCK TABLES テーブル名[AS エイリアス]{READ [LOCAL]|[LOS_PRIORITY]WRITE}
- READ: 読み取りロック。ユーザーはテーブルを読み取ることができますが、テーブルを変更することはできません。
- WRITE: 書き込みロック。テーブルをロックしたユーザーだけがテーブルを変更でき、他のユーザーはテーブルを読み取ることしかできません。
- インテンションロック: ロックの粒度はテーブル全体です。インテンション ロックとは、インテント ロックがノードに適用される場合、そのノードの基になるノードがロックされていることを意味します。インテント ロックは、インテント共有ロック (IS)とインテント排他ロック (IX)の 2 つのタイプに分類されます。これは、MySQL がテーブルに自動的に追加するロックです。主な機能はシステム パフォーマンスを向上させることです。それ以外の場合、2 番目のトランザクションがロックするたびに、テーブルがロックされているかどうかを確認し、次に行がロックされているかどうかを確認する必要があり、パフォーマンスが大幅に消費されます。
行レベルのロック: スレッドによって使用される行のみがロックされます。テーブル内の他のすべての行は、他のスレッドで使用できます。行レベルのロックは、読み取りロックと書き込みロックに分割されます。
- READ: 読み取りロック。ユーザーはテーブルを読み取ることができますが、テーブルを変更することはできません。
- WRITE: 書き込みロック。テーブルをロックしたユーザーだけがテーブルを変更でき、他のユーザーはテーブルを読み取ることしかできません。
ギャップ ロック:ギャップ ロック (Gap Lock)は、ファントム読み取りとデータ削除の問題を解決するために、反復読み取り分離レベルで InnoDB エンジンによって導入されたロック メカニズムです。select * from test where id > 0 and id < 5 for update;, テーブル内に ID 2 のデータがない場合 (1、3、4 のみ)、ID=2 のデータは「ギャップ」と呼ばれ、InnoDBエンジンはこれらの「ギャップ」もロックします。この時点で、トランザクション T2 が INSERT ステートメントを実行し、ID が 2 のデータを挿入する場合、正常に挿入するにはトランザクション T1 が終了するまで待つ必要があります。
ロックコマンド
共有ロックを設定します: SELECT * FROM テーブル名 WHERE 条件 LOCK IN SHARE MODE;
排他ロックの設定: SELECT * FROM テーブル名 WHERE 条件 FOR UPDATE; (InnoDB エンジンは、デフォルトの変更ステートメントの更新、削除、挿入に排他ロックを自動的に追加します)
ロック待機中
ロック待機とは、トランザクションの実行中に、リソースを使用する前に、前のトランザクションのロックが解放されるまでロックを待機する必要があることを意味します。
パラメータ:
- innodb_lock_wait_timout : ロック待機時間パラメータ
- select * from sys.innodb_lock_waits\G : ロック待機の発生を表示
- show full processlist : スレッド ID 番号を出力
デッドロック
MySQL の InnoDB ストレージ エンジンでは、デッドロックが検出されると、通常、最も行レベルの排他ロックを保持しているトランザクションが解放されてロールバックされますが、別のトランザクションはロックを取得してトランザクションの完了を続行できます。
トランザクションとロックを監視する
トランザクションおよびロック情報を表示および監視するには、 show Engine innodb statusコマンドを実行します。
MySQL はトランザクションとロックの情報をinformation_schemaデータベースに記録します。必要なのはクエリだけです。主に、innodb_trx (トランザクション ステータスの確認)、innodb_locks (ロック ステータスのクエリ)、innodb_lock_waits (ロック ブロック ステータスの確認) という 3 つのテーブルが関係します。
MySQL 5.6 以降のバージョンでは、innodb_print_all_deadlocks パラメータを 1 に設定してデッドロック情報を記録し、エラー ログに記録できます。
デッドロックを回避する方法
デッドロックを回避する方法
(I) 異なるプログラムが複数のテーブルに同時にアクセスする場合、または複数行のレコードに関係する場合は、同じ順序でテーブルにアクセスすることに同意するようにしてください。これにより、デッドロックの可能性を大幅に減らすことができます。
(2) アプリケーション プログラムを調整する場合によっては、大きなトランザクションを複数の小さなトランザクションに分解することで、ロックの解放が速くなり、トランザクションを時間内にコミットまたはロールバックできるようになり、デッドロックの可能性を減らすことができます。
(3) 同じトランザクション内で、デッドロックの可能性を減らすために、必要なすべてのリソースを一度にロックするようにしてください。
(4)適切なインデックスをテーブルに追加します。インデックスが使用されていない場合、テーブルの各行がロックされ、デッドロックの可能性が大幅に増加します。
(5) デッドロックが非常に発生しやすいビジネスの場合は、ロックの粒度をアップグレードし、テーブル ロックを通じてデッドロックの可能性を減らすようにしてください。