この記事では、mysql のロックのさまざまなタイプとモードに関する関連知識を提供します。お役に立てば幸いです。
日常の開発業務では、ほぼ毎日データベースを扱う必要があり、CRUDしか知らないSQL BOYとしては、mybatis-generatorを使用して自動生成するだけでなく、毎日 DAO 層のコードを処理しているほか、データベースでの同時リクエストの処理についてはほとんど気にする必要がありませんが、ある日突然 MYSQL データベースのアラートが発生し、デッドロックが発生してしまい、心の中でパニックになってしまい、どうすることもできません。不思議: これは単なる普通のクエリではないでしょうか? まだロックされていますか?
パニック表現がスーパーバイザによってキャプチャされるのを避けるために、データベースにどのようなロックがあるかを事前に知っておく必要があります。
MySQL では、ロックは実際には、ロック タイプ (lock_type) とロック モード (lock_mode) の 2 つのカテゴリに分類されます。
ロック タイプはロックの粒度、つまりロックが具体的に追加される場所を表し、ロック モードは追加されるロックの種類 (読み取りロックか書き込みロックか) を表します。ロック モードは、多くの場合、ロック タイプと組み合わせて使用されます。
読み取りロック
読み取りロック。共有ロック/S ロック/共有ロックとも呼ばれます。 。
読み取りロックは、読み取り操作 (テーブルの読み取りや行の読み取りなど) を実行するときにトランザクション (トランザクション A など) によって作成されるロックです。他のトランザクションはこれらのデータを同時に読み取ることができます。(ロック済み)、ただし、データは変更できません (ロックを保持しているユーザーがロックを解除しない限り)。
トランザクション A がデータに読み取りロックを追加した後、他のトランザクションは引き続き読み取りロック (共有) をデータに追加できますが、書き込みロックを追加することはできません。
レコードに読み取りロックを追加
InnoDB は、テーブル ロックと行ロック、行 (つまりレコード) のロック、および代わりにレコードをロックすると、レコードに対応するインデックスもロックされます。 where 条件にインデックスがない場合、すべてのレコードがロックされます。
明示的なロック ステートメントは次のとおりです。
注: ここで説明する読み取りは現在の読み取りを指し、スナップショット読み取りにはロックは必要ありません。通常の選択読み取りは、現在の読み取りになる共有モードの select...lock などの明示的なロック ステートメントを除き、通常はスナップショット読み取りです。InnoDB エンジンのシリアル化可能レベルでは、通常の選択読み取りもスナップショット読み取りになります。
また、ロウロックのロック処理の分析には、トランザクション分離レベル、インデックスを使用するかどうか(どの種類のインデックスか)、レコードが存在するかどうか、およびレコードを追加する場所を決定するその他の要因。
innodb エンジンに読み取りロックを追加するいくつかの状況
分離レベルがシリアル化可能である場合、通常のクエリはレコードに S ロックを追加します。ただし、これはシナリオにも依存します: 非トランザクション読み取り (自動コミット) には、シリアル化可能分離レベルでのロックは必要ありません。
シリアル化可能分離レベル: クエリ条件が一意のインデックスと一意の等しい値の場合クエリ: レコードに S ロックを追加します; 非一意条件クエリ (クエリが複数のレコードをスキャンする場合): レコード自体のギャップ (ギャップの範囲を具体的に分析する必要があります)、S ロックを追加します;
select ... 共有モードでは、S ロックがレコードに追加されますが、ロックの動作は分離レベルによって異なります。
RC 分離レベル: S ロックがレコードに追加されます。 RR/シリアル化可能分離レベル: クエリ条件が一意のインデックスおよび一意の等しい値クエリの場合: S ロックがレコードに追加されます; 非一意条件クエリ (クエリが複数のレコードをスキャンする場合): レコード自体間のギャップ(ギャップの範囲を具体的に分析する必要があります)、S ロックを追加します;
通常、挿入操作はロックされませんが、レコードの挿入または更新時に重複キーが検出された場合 (または、重複したキーが存在する場合)は削除対象としてマークされています) キー)、通常の挿入/更新の場合は S ロックが追加され、重複に対する replace into または insert ... のような SQL ステートメントの場合は X ロックが追加されます。
insert ... select データを挿入するとき、select テーブルでスキャンされたデータに S ロックが追加されます;
外部キー チェック: 親テーブルのレコードを削除するときに、参照制約があるかどうかを確認する必要があります。このとき、サブテーブル上の該当するレコードがスキャンされ、S ロックが追加されます。
テーブルへの読み取りロックの追加
テーブル ロックは MySQL サーバーによって実装され、ストレージ エンジンに関係なく使用できます。一般に、ALTER TABLE などの DDL ステートメントを実行すると、テーブル全体がロックされます。 SQL ステートメントの実行時にテーブルを明示的にロックすることもできます。
テーブルの明示的なロック ステートメントは次のとおりです:
MYISAM エンジンを使用する場合、通常は手動でロックする必要はありません。私たちをターゲットにします SQL ステートメントは自動的にロックされ、プロセス全体でユーザーの介入は必要ありません:
クエリ ステートメント (選択): 読み取りロックは関係するテーブルに自動的に追加されます。
#書き込みロック
書き込みロック、排他ロック/X ロック/排他ロック。書き込みロックのブロック特性は読み取りロックよりもはるかに厳密で、トランザクションがデータに書き込みロックを追加すると、他のトランザクションはデータの読み取りも変更もできなくなります。 読み取りロック、書き込みロックと同じ範囲をレコードまたはテーブルに追加できます。レコードに書き込みロックを追加します
レコードに書き込みロックを追加します。エンジンは InnoDB を使用する必要があります。 通常、通常の select ステートメントはロックしません (分離レベルがシリアル化可能である場合を除く)。クエリ中に排他的ロックを追加したい場合は、次のステートメントを使用する必要があります: Add writeクエリ中のロック: 読み取りロックを追加するのと同じように、書き込みロックもインデックスに追加されます。 更新時に書き込みロックを追加:テーブルに書き込みロックを追加
テーブルに書き込みロックを明示的に追加するステートメントは次のとおりです: エンジンが myisam を選択すると、挿入/更新/削除ステートメントによって排他ロックが自動的にテーブルに追加されます。テーブル。 読み取り/書き込みロックの互換性:インテンション ロックインテンション ロックは、競合しないテーブル レベルのロックです。行レベルのロックを使用して、ロックのタイプ (S ロックまたはInnoDB は複数の粒度ロックをサポートしており、行レベルのロックとテーブルレベルのロックの共存が可能です。
インテンション ロックは次のように分類されます。
インテンション共有ロック (IS ロック): IS ロックは、現在のトランザクションがテーブル内の行に共有ロックを設定することを意図していることを示します
When次のステートメントが実行されます。この操作は S ロックを取得しているため、IS ロックが最初に取得されます。S ロックを取得します。select ... lock in share mode
意図排他ロック (IX ロック): IX ロックは、現在のトランザクションの目的がテーブル内にあることを示します。 行に排他ロックを設定します。
次のステートメントが実行されると、この操作は X ロックを取得しているため、最初に IX ロックが取得されます。 X ロック: select... for update
取得するトランザクション 特定のテーブルの S ロックと X ロックを取得する前に、対応する IS ロックと IX ロックをそれぞれ取得する必要があります。
インテンション ロックの役割:
別のトランザクションがテーブル レベルで共有ロックまたは排他ロックを試行すると、最初のトランザクションによって制御されるテーブル レベルのインテンション ロックの影響を受けます。 。 ブロック。 2 番目のトランザクションでは、テーブルをロックする前に個々のページまたは行のロックをチェックする必要はありませんが、テーブルのインテント ロックのみをチェックする必要があります。
例: テーブル test_user:
##トランザクション A は行の排他ロックを取得しましたが、コミットしませんでした。
トランザクション B は、test_user テーブルのテーブル共有ロックを取得しようとしています;##共有ロックと排他的ロックは相互に排他的であるため、トランザクション B が test_user テーブルに共有ロックを追加しようとすると、
現在、他のトランザクションが users テーブルに対して排他ロック (テーブル排他ロック) を保持していないことを確認する必要があります。
現時点では、users テーブルの行に対して排他ロック (行排他ロック) を保持しているトランザクションは他にありません。
2 番目の条件が満たされているかどうかを確認するために、トランザクション B は、test_user に排他ロックがないことを確認しながら、テーブル内の各行に排他ロックがあるかどうかを確認する必要があります。テーブル。明らかにこれは非常に非効率なアプローチですが、インテンション ロックの場合は状況が異なります。
トランザクション B は、test_user テーブルの共有ロックを取得したいと考えています。
トランザクション B は、トランザクション A が test_user テーブルの意図された排他ロックを保持しているかどうかを検出するだけでよく、その後、それを知ることができます。トランザクション A は、テーブル内の特定のデータ行に排他ロックがある場合、test_users テーブルに対するトランザクション B のロック要求が除外 (ブロック) されるため、トランザクションの各行に排他ロックがあるかどうかを検出する必要はありません。テーブル内のデータ。
トランザクション C は、users テーブル内の行の排他ロックも取得したいと考えています。
トランザクション C は、トランザクション A が test_user テーブルに対して意図された排他ロックを保持していることを検出します。 ;
インテンション ロックは相互に排他的ではないため、トランザクション C は test_user テーブルのインテンション排他ロックを取得しました。 ID は 31 です。排他ロックはありません。最終的に、トランザクション C はデータ行の排他ロックを正常に取得します。
インテンション ロックは相互排他的ではありませんが、次のようにインテンション ロックと他のテーブル ロックの間にはある程度の互換性と相互排他があります。
インテンション ロック間の互換性と相互排他性:
# インテンション ロックと通常の排他/共有ロック間の相互排他性:
自動増加ロック
テーブル構造を設計するとき、通常、主キーを自己増加に設定します (理由を考えてください)。
InnoDB ストレージ エンジンでは、自己増加フィールドごとに自己増加カウンタが設定されます。次のステートメントを実行して、このカウンターの現在値を取得できます:
#挿入操作を実行するとき、操作はこのカウンターの現在値に基づいて実行されます。自己増加カウンタ。1 つの操作を実行し、それを自己増加列に割り当てます。この操作は auto-inc ロックと呼ばれ、自動インクリメント ロックです。このロックは実際には特殊なテーブル ロック メカニズムを使用します。挿入操作がトランザクション、これ ロックは、トランザクションのコミットを待つのではなく、挿入操作の完了後すぐに解放されます。
グローバル ロック
いわゆるグローバル ロックは、実際にはデータベース インスタンス全体をロックします。 。
データベース インスタンスとデータベースには違いがあります:
データベースはデータを保存する倉庫です。特に mysql では、データベースは実際にはデータ ファイルのコレクションです (これが実際にはデータ ファイルのコレクションです)通常、データベースを呼び出します。たとえば、データベースを作成するステートメントは create database... です)。
データベース インスタンスとは、データベースにアクセスするアプリケーション プログラムを指し、Mysql では mysqld プロセスに相当します。
簡単に理解すると、データベース インスタンスには、作成したさまざまなデータベースが含まれます。
データベース インスタンスにグローバル ロックを追加すると、ライブラリ全体が読み取り専用状態になります (これは非常に危険です)。
一般的に、グローバル ロックの一般的な使用シナリオは、データベースの完全バックアップ、つまりデータベース内のすべてのテーブルを選択することです。ただし、ライブラリ全体を読み取り専用状態のままにしておくと、いくつかの深刻な問題が発生することに注意してください:
メイン ライブラリにグローバル ロックを追加します。ロック期間中は、更新操作は行われません。 , ビジネスの多くの機能は基本的に利用できません;
スレーブ データベースにグローバル ロックを追加します。ロック期間中は、マスターとスレーブの同期は実行できません。マスターとスレーブの同期遅延が発生します。
#グローバル ロックを解放する方法は次のとおりです:
ダンプ ツールはすでにあるのに、なぜ FTWRL が必要なのでしょうか?一貫した読み取りは良好ですが、これはエンジンがこの分離レベルをサポートしている場合に限られます。たとえば、MyISAM のようなエンジンはトランザクションをサポートしません。このとき、FTWRLコマンドを使用する必要があります。
FTWRL の前に読み取りまたは書き込みがある場合、FTWRL は読み取りおよび書き込みが完了するのを待ってから実行します。
FTWRL を実行すると、ダーティ ページ データをディスクにフラッシュする必要があります。データの整合性を維持する必要があるため、FTWRL はすべてのトランザクションが送信されたときに実行されます。
グローバル ロックの実装は依然としてメタデータ ロックに依存しています。
メタデータ ロックメタデータ ロック (MDL ロックとも呼ばれる) は、システム レベルでメタデータ情報を保護するために使用されます。ロックをアクティブに行うことはできません。制御されている。 MySQL バージョン 5.5 では、主に同時環境での DDL と DML の同時操作下でメタデータの一貫性を維持するために、MDL ロックが導入されました。たとえば、次の状況:
分離レベル: RR
メタデータ ロックの保護がない場合、トランザクション 2 は DDL 操作を直接実行できます。トランザクション 1 エラーが発生します。この状況が起こらないようにするために、MDL ロックが MYSQL5.5 バージョンに追加されました。トランザクション 1 はクエリを開始するため、メタデータ ロックを取得します。ロック モードは MDL 読み取りロックです。トランザクション 2 が DDL を実行する場合は、MDL 書き込みロックを取得する必要があります。読み取りロックと書き込みロックは相互に排他的であるため、トランザクション 2トランザクション 1 が解放されるまで待機する必要があります。読み取りロックが解放された場合にのみ実行できます。
MDL ロックの粒度
MDL ロックは、ストレージ エンジンではなく、Mysql サーバー レベルで実装されます。プラグインで実現しました。ロックの範囲に応じて、MDL ロックは次のカテゴリに分類できます:
#MDL ロック モード
##ページ レベル ロック ##MySQL のロック粒度は、行レベルのロックとテーブル レベルのロックの間です。テーブルレベルのロックは高速ですが競合が多く、行レベルのロックは競合がほとんどありませんが低速です。そこで、隣接するレコードのグループを一度にロックする、侵害されたページ レベルが採用されました。ストレージ エンジンが異なれば、サポートされるロック メカニズムも異なります。さまざまなストレージ エンジンに応じて、MySQL のロックの特徴は次のように大まかに要約できます。
ページレベルのロックは、MySQL の独自のロック レベルであり、次のように適用されます。 BDB エンジン。同時実行性は平均的です。ページ レベルのロックの特徴は、ロックの粒度が行レベルのロックとテーブル レベルのロックの中間にあることです。そのため、ロックを取得するために必要なリソース オーバーヘッドと、ロックを取得するために必要な同時処理能力が異なります。 Provide も上記 2 つの間にあります。さらに、ページレベルのロックと行レベルのロックによりデッドロックが発生します。
ロック粒度サイズの比較: テーブル レベルのロック > ページ レベルのロック > 行レベルのロック テーブル レベルのロック# #テーブル ロックについては上で紹介しましたが、行ロックのきめ細かいロックと比較して、テーブル ロックはテーブル全体をロックします。テーブル全体がロックされるため、行ロックほど複雑ではありません。そのため、ロックは行ロックより高速で、デッドロックは発生しません(トランザクションは一度に必要なテーブル ロックを取得するため)。ただし、テーブル ロックにはいくつかの制限もあります。問題: ロック範囲が大きすぎ、同時実行性が比較的高い場合、ロック競合の可能性が増加し、同時実行パフォーマンスが大幅に低下します。
テーブル ロックのロック方法
エンジンが MYISAM を選択する場合MYISAM エンジンはテーブル ロックのみをサポートし、テーブル ロックはサポートしません。行ロック。
テーブル レベルのロックを手動で追加するステートメントは次のとおりです:
MYISAM エンジンを使用する場合、通常はロックを手動で追加する必要はありません。 MYISAM エンジンが私たちをターゲットにするため、SQL ステートメントは自動的にロックされ、プロセス全体がユーザーの介入を必要としません。クエリ ステートメント (選択): 読み取りロックが自動的に追加されます。関連するテーブル;
Update ステートメント (更新、削除、挿入): 書き込みロックが関連するテーブルに自動的に追加されます
InnoDB エンジンは行レベルのロックとテーブルレベルのロックの両方をサポートしており、デフォルトは行レベルのロックです。 InnoDB エンジンのテーブルを手動でロックし、ロック テーブル {tableName} 読み取り/書き込みステートメントを使用して読み取り/書き込みロックを追加します。
さらに、innodb はテーブルレベルのロック、つまりインテンション ロック (すでに上で紹介されています) もサポートしています。
一般に、InnoDB エンジンのテーブル レベルのロックには 5 つのロック モードが含まれます。
LOCK_IS: 意図的な読み取りロック
LOCK_IX: テーブル意図書き込みロック
##LOCK_AUTO_INC: 自己増加ロック
競合がほとんどありません: 複数のスレッドで異なるレコードにアクセスするときにロックの競合がほとんどありません。
ロックの粒度は小さいため、他の行に影響を与えることなく単一の行を長期間ロックできるため、同時実行性が最も高くなります。
ただし、次を使用します。行ロック 注意しないと非常に簡単にデッドロックが発生するため(デッドロックにはテーブルロックが存在しません)、行ロックを使用する場合は、ロック順序とロック範囲に注意する必要があります。
覚えておく必要があります: 行ロックはレコード ロックとも呼ばれ、レコード ロックはインデックスに追加されます。
条件で主キー インデックスを指定します: その後、主キー インデックスをロックします;
条件で副次インデックスを指定します: レコード ロックはこのセカンダリ インデックスに追加されるだけでなく、このセカンダリ インデックスに対応するクラスタード インデックスにも追加されます;
どこ条件 インデックスにアクセスできない場合: MySQL はレコード全体のロックを与えます。テーブル内のすべてのデータ行に追加され、ストレージ エンジン層はフィルタリングのためにすべてのレコードを MySQL サーバーに返します。
レコード ロックは常にインデックスに追加されます。テーブルにインデックスがない場合でも、データベースは暗黙的にインデックスを作成します。 WHERE 条件で指定した列がセカンダリ インデックスの場合、セカンダリ インデックスだけでなく、セカンダリ インデックスに対応するクラスタード インデックスにもレコード ロックが追加されます。
SQL ステートメントがインデックスを使用できない場合、メイン インデックスを使用してテーブル全体のスキャンが実行されることに注意してください。このとき、MySQL はテーブル全体のすべてのデータ行にレコード ロックを追加します。
WHERE 条件をインデックスですぐにフィルタリングできない場合、ストレージ エンジン層はすべてのレコードをロックして返し、その後 MySQL Server 層がそれらをフィルタリングします。インデックスが存在しない場合、大量のロック リソースが消費され、データベースのオーバーヘッドが増加するだけでなく、データベースの同時実行パフォーマンスも大幅に低下します。そのため、更新操作中にインデックスを使用することを忘れないでください (理由は次のとおりです)。更新操作により X ロックが追加されます)。
いくつかの種類の行レベル ロック:
ギャップ ロック: LOCK_GAP (ロック ギャップのみ)
ギャップ ロックはレンジロック。ロックは、存在しない空き領域、2 つのインデックス レコード間、最初のインデックス レコード、または最後のインデックスの後のスペースに追加され、範囲のみがロックされていることを示すために使用されます (通常、範囲クエリを実行する場合は分離して使用されます)。 ) RR またはシリアル化可能な間隔のレベル)。
一般に、GAP ロックは RR 分離レベルで使用されます。 GAP ロックを使用する主な目的はファントム読み取りを防止することであり、GAP ロックによってロックされた区間ではデータの挿入や更新ができなくなります。
ギャップロック生成の条件: innodb の分離レベルは、Repeatable Read または Serializable です。
ギャップ ロックの範囲の説明:
分離レベル: RR
Student テーブルをサンプル データとして、ID を ID として取得します。主キーの stu_code は学生番号で、通常のインデックスが追加されます。
ギャップ ロック領域の定義:
検索条件に従って、左側の間隔として最も近い値 A を探し、右側の間隔として最も近い値 B を探します。ギャップ ロックは ( A, B) です。
最も近い値 A は、無限小である左に見つかりません。左の間隔として、最も近い値 B が右の間隔として右に見つかります。ギャップ ロックは (infinitesimal, B)
左の間隔として左に最も近い値 A を見つけ、右の間隔として右に最も近い値 B (無限大) を見つけます。ギャップロックは (A, 無限大)
Interval (A,B) 例:
トランザクション 1:
select * from student where stu_code = 4 for update
トランザクション 2:
insert into student vaues(2, 2, 'A'); insert into student values(4, 5, 'B');
トランザクション 1 の SQL ステートメント分析、ギャップ ロックの範囲は次のとおりです。 stu_code = 4 レコードが存在するため、左側の間隔の最新のインデックス値は stu_code = 3、右側の間隔の最新のインデックス値は stu_code = 7、つまりギャップ範囲は次のとおりです: (3, 7) トランザクション 2 の 2 つの挿入ステートメント、1 つは範囲外で、もう 1 つは範囲内です。範囲外のものは挿入できますが、範囲内のものは挿入できます。範囲はブロックされているため、(2, 2, 'A') は正常に挿入できますが、(4, 5, 'B') はブロックされて挿入されます。
間隔 (無限小、B) 例:
トランザクション 1:
select * from student where stu_code = 1 for update
トランザクション 2:
insert into student vaues(2, 0, 'c'); insert into student vaues(2, 2, 'r'); insert into student vaues(5, 2, 'o');
トランザクション 1 の SQL ステートメント分析によると、ギャップ ロック 範囲は次のとおりです: stu_code = 1 が存在し、左側に最近のレコードがないため、左側は無限小で、右側の最も近いインデックス値は stu_code = 3 であるため、ギャップ ロックの範囲は次のようになります: (無限、3)。したがって、トランザクション 2 の最初と 2 番目の挿入 SQL ステートメントの実行はブロックされ、ギャップ ロックの範囲内になります。 3 番目の insert SQL ステートメントは正常に実行できますが、ギャップ ロックの範囲内ではありません。
Interval (A, 無限大) 例:
トランザクション 1:
select * from student where stu_code = 7 for update
トランザクション 2:
insert into student vaues(2, 2, 'm'); insert into student vaues(20, 22, 'j');
トランザクション 1 の SQL ステートメント分析によると、ギャップ ロックの範囲は次のとおりです: stu_code = 7 が存在し、左側の最も近いインデックス値は stu_code = 4、右側にはインデックス値がないため、ギャップ ロックの範囲は次のようになります: (4, 無限大)、最初のinset ステートメントは正常に実行できますが、ギャップ範囲内ではありません。2 番目の挿入ステートメントの実行はブロックされ、ギャップ ロック範囲内にあります。
クエリ ステートメントがデータベースに記録されていない場合、それをロックするにはどうすればよいですか?
上記はクエリが記録されているということですが、クエリ文がデータベースに記録されていない場合、どのようにロックすればよいのでしょうか?続けてみましょう:
トランザクション 1:
update student set stu_name = '000' where stu_code = 10
トランザクション 2:
insert into student vaues(2, 2, 'm'); insert into student vaues(20, 22, 'j');
上記の実行ステートメントによると、レコードが見つからず、最も近いレコードが取得されます。 left (10, 7, 'Xiao Ming') を左の間隔として指定します。つまり、ギャップ ロックの範囲は次のとおりです: (7, infinity)。最初の挿入ステートメントは間隔の範囲内にないため、正常に実行できます。 2 番目の挿入実行ステートメントは間隔内でブロックされ、実行は失敗しました。トランザクション 1 の where 条件が 10 より大きい場合、最も近いレコード値も左側の間隔として左側に見つかるため、ギャップ ロックの範囲も次のようになります: (7, 無限大)
概要:ギャップ ロックの生成条件
RR/Serializable 分離レベルの下: Select...Where...For Update: 一意のインデックス クエリのみを使用し、1 つのレコードのみをロックする場合、InnoDB行ロックを使用します。 ユニークインデックスクエリのみを使用し、検索条件が範囲検索の場合、または検索結果がユニーク検索でも存在しない場合(存在しないデータをロックしようとした場合)、ネクストキーロックが発生します。 通常のインデクス検索では、どのようなクエリであっても排他がかかっている限りギャップロックが発生します。ユニーク インデックスと通常のインデックスを同時に使用する場合、データ行は最初に通常のインデックスに従って並べ替えられ、次にユニーク インデックスに従って並べ替えられるため、ギャップ ロックも発生します。
Next-Key ロック: LOCK_ORDINARY (Next-Key Lock とも呼ばれる)
Next-Key ロックは、レコード ロック ギャップ ロックの組み合わせです。 。ギャップ ロックと同様、RC 分離レベルの下にはネクスト キー ロックはなく (構成を変更して強制的にオンにしない限り)、RR/シリアル化可能分離レベルのみにあります。
MySQL InnoDB は反復読み取り分離レベル (RR) で動作し、Next-Key Lock を使用してデータ行をロックします。これにより、ファントム読み取りの発生を効果的に防止できます。 Next-Key Lock は、行ロックとギャップ ロックの組み合わせです。InnoDB がインデックス レコードをスキャンするとき、最初に行ロック (レコード ロック) をインデックス レコードに追加し、次にギャップ ロック (ギャップ ロック) をギャップに追加します。インデックスレコードの両側にあります。ギャップ ロックを追加すると、他のトランザクションはこのギャップ内のレコードを変更したり挿入したりできなくなります。
クエリされたインデックスに一意の属性 (一意のインデックス、主キー インデックス) が含まれている場合、Innodb ストレージ エンジンはネクスト キー ロックを最適化し、レコード ロックに削減します。つまり、代わりにインデックス自体のみをロックします。範囲の。
挿入意図ロック: LOCK_INSERT_INTENSION
レコードを挿入するときに使用される挿入意図ロックは、特殊なギャップ ロックです。このロックは挿入の意図を表します。このロックは、挿入ステートメントが実行されるときにのみ存在します。
インデックス レコードの値が id = 1 と id = 5 であると仮定します (1 と 5 の間にレコードはありません)。別のトランザクションは、それぞれ id = 2 と id = 3 を挿入しようとします。挿入された行の取得 排他ロックが使用される前は、各トランザクションは挿入意図ロックを使用して 1 と 5 の間のスペースをロックしましたが、相互にブロックすることはありませんでした。挿入されたインテンション ロック間に競合が発生しないためです。
インテンション ロックの挿入は、ギャップ ロックまたは Next-Key ロックと競合します。ギャップ ロックの機能は、他のトランザクションがデータを挿入してファントム読み取りを引き起こすのを防ぐために間隔をロックすることです。
上記のシナリオでは、トランザクション A が事前に (1, 5) の範囲の id を持つギャップ ロックを取得していると仮定すると、トランザクション B が id = 2 を挿入しようとすると、最初に取得を試みます。挿入意図ロックが存在しますが、挿入意図ロックとギャップ ロックが競合するため、挿入は失敗し、ファントム リードの発生が回避されます。
#結論
MYSQL のロック機構は非常に複雑なので、実際の開発作業では分離レベルの設定に細心の注意を払う必要があります。 RR レベルには RC レベルよりも 1 つ多くのギャップ ロックがあり、深刻なパフォーマンス上の問題が発生する可能性があります。この記事では、ロック モードとロック スコープの観点から MYSQL ロックの分類を簡単に紹介しますが、データベース開発のプロセスでは、SQL ステートメントが合理的であるかどうかを慎重に分析および検討できることを願っています (特に、デッドロックやその他の問題が発生します)。)! 推奨学習:以上がMYSQL のさまざまなモードとロックの種類について話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。