blog

Mysql-InnoDBのロックの仕組みとテスト

1. デッドロック 1.1 デッドロックの概念: デッドロックとは、実行プロセスにおいて、2つ以上のプロセスが、互いに待ち合う現象に起因するリソースの奪い合いにより、外力がなければ前に進めなくなること...

Aug 12, 2020 · 5 min. read
シェア

デッドロック

デッドロックの概念:

デッドロックは、実行プロセス内の2つ以上のプロセスを指し、リソースの競合のために、お互いを待っている現象によって引き起こされる、外力がなければ、彼らは前進することはできません。この場合、システムはデッドロック状態であるか、システムがデッドロックを生成すると言われ、これらのプロセスは常にお互いを待っているデッドロックプロセスと呼ばれます。テーブルレベルのロックではデッドロックは発生しません。そのため、デッドロックの解決策は、主に最も一般的に使用されるテーブルロックであるInnoDBに焦点を当てています。

mysqlデッドロックの対処法

  1. タイムアウトが切れるまで待ちます。
  2. デッドロックの検出を開始し、トランザクションを積極的にロールバックして、他のトランザクションが実行を継続できるようにします。

デッドロックの検出

デッドロック検出の原理は、トランザクションを頂点、ロックを辺とする有向グラフを構成し、有向グラフ内にリングがあるかどうかを判定し、リングがあればデッドロックあり。

ロールバック機構

デッドロックが検出されると、INFORMATION_SCHEMA.INNODB_TRXテーブルのtrx_weightフィールドに基づいて、挿入、更新、削除された行数が最も少ないトランザクションがロールバックされます。挿入、更新、削除された行の数が同じであれば、後のトランザクションがロールバックされます。

試験表およびデータ:以下には記載なし。

p_transactionテーブル

id int(11) NO PRI auto_increment
count int(11) YES 
version int(11) YES 0 
---
id count version
1 1 1
6 11 0
10 14 0
11 14 0
12 10 0
13 15 0
14 16 0
15 17 0
16 18 0
21 22 0
24 24 0
25 25 0
26 26 0
27 27 0
28 28 0
29 29 0
30 300 0
31 301 0

テストケース

-- ログファイルの設定状況を確認する
show variables like "%innodb_flush_log_at_trx_commit%";
-- ログファイル設定のステータスを変更する
set @@global.innodb_flush_log_at_trx_commit = 0; -- 0,1,2
-- ロックの待ち時間
show VARIABLES like "%innodb_lock_wait_timeout%";
-- デッドロックの自動ロールバック
show VARIABLES like "%innodb_deadlock_detect%";
-- デッドロックテスト
begin;
select * from p_transaction where id = 32 for update;
update p_transaction set count = 1 where id = 1;
insert into p_transaction (id, count) values (32, 300);
commit;
rollback;

MVCC

MVCCはInnoDBがトランザクション分離レベルで一貫性のある読み取り操作を実行することを可能にします。クエリは他のトランザクションがロックを解放するのを待つ必要がないため、これは同時実行性を高めるために使用できる強力なテクニックです。このテクニックはデータベースの世界では一般的ではありません。他のデータベース製品やmysqlの他のストレージエンジンではサポートされていないものもあります。

mysqlのinnodbテーブルは、実際のデータに加えて、以下のように3つの隠しフィールドを追加します。

actual_data|create_no(create_version_number or create_time)|update_no(version_number_of_each_modification_or_modify_time)|delete_no(delete_version_number_or_delete_time)

  • insert:新しいデータが追加されると、作成されたデータのバージョン番号が追加されます。
  • update: 現在のフィールドを変更します。データが変更されるたびに、変更されたバージョン番号が順次インクリメントされます。
  • 削除:現在のデータを削除し、実際には、削除されません、彼は最初のバージョン番号フィールドで削除されたバージョン番号を記録するために削除されます、時間の期間の後にクリアまたはリフレッシュされます

MVCCは楽観的ロックの実装ですが、MVCCが楽観的ロックと同等かというとそうではありません。

テストケース

-- 楽観的ロックテスト
select count, version from p_transaction where id = 1;
update p_transaction set count = count - 1,version = version + 1 where id = 1 and version = 0;

楽観的ロックと悲観的ロック: 楽観的ロックと悲観的ロックはアイデアであり、実際のmysqlのロック機構ではありません。

楽観的ロック:ロック機構は使用しません。

悲観的ロック:ロック・メカニズムが使われるときは常に悲観的ロックです。

テストケース

-- 悲観的ロックテスト
begin;
select count from p_transaction where id = 1;
update p_transaction set count = count - 1 where id = 1;
commit;
rollback;

ギャップロック

均等条件ではなく、条件範囲を指定してデータを取得し、共有ロックまたは排他ロックを要求する場合、InnoDBは条件を満たす既存のデータレコードのインデックス項目をロックします。"ギャップ "と呼ばれる、存在しない条件範囲内のキー値を持つレコードについては、InnoDBはこの "ギャップ "にもロックを追加し、このロック機構をギャップロックロックと呼びます。"ロック"、このロック機構がいわゆるギャップロックロックです。このロックメカニズムはギャップロックと呼ばれます。 ギャップロックはページレベルのロックに似ていますが、実際には行レベルのロックです。

テストケース

-- 悲観的ロックテスト
begin;
select count from p_transaction where id = 1;
update p_transaction set count = count - 1 where id = 1;
commit;
rollback;

行レベルロックのテーブルレベルロックへのアップグレード

InnoDBの行レベルロックは、インデックス上のインデックス項目にロックを追加することで達成されます。InnoDBの行レベルロックは、インデックス条件を通してデータを取得する場合にのみ使用されます。

テストケース

-- ギャップロックテスト
begin;
select * from p_transaction where id >=1 and id <= 10 for update;
select * from p_transaction where id between 1 and 10 for update;
--  
select * from p_transaction where id = 6 for update;
--  
select * from p_transaction where id = 6 lock in share mode;
--  
select * from p_transaction where id = 6;
update p_transaction set count = 10 where id = 6;
update p_transaction set count = 10 where id = 12;
commit;
rollback;

トランザクションの使用に関する推奨事項

  1. ロックされるリソースの量とロック時間の長さを減らすために、トランザクションサイズを制御します。
  2. 人のデータ検索はすべてインデックスを通して行われるため、インデックスを通してロックすることができず、テーブルロックへのエスカレーションを避けることができます。
  3. 範囲ベースのデータ検索フィルタを減らして、ギャップ・ロックの悪影響によりロックすべきでないデータをロックしないようにします。
  4. ビジネス・コンディションが許す限り、トランザクションの分離に低い分離レベルを使用するようにしてください。分離レベルに関連する追加コストを削減します。
  5. インデックスの上にロックを追加する時、innodbがより正確になるようにインデックスを賢く使ってください。
  6. 可能な限りアプリケーション内でアクセスを逐次実行
  7. デッドロックが発生しやすい場合は、デッドロックの確率を下げるためにテーブルロックの使用を検討してください。
Read next

47.Vueはchildren属性を使ってルートの入れ子を実装する。

この文章では直接説明できないかもしれませんが、直接例を見てみると以下のようになります。 上記からわかるように、regsterとログイン経路のパスを書いていますが、実は、/account経路では、あまりやることがありません。 単にプレフィックスを書くだけです。 親コンポーネントのアプリは、直接しかできないことがわかります...

Aug 12, 2020 · 4 min read