目次
1.3. InnoDB 行ロックはトランザクションをサポートします
1.3.4. ケースの準備 innodb はトランザクションの行レベルのロックをサポートします
1.3.5. 行ロックの基本的なデモ - トランザクションのサポート
1.ロック
1.1. MySQL ロックの問題
1.1.1. ロックの概要
ロックは、(競合を避けるために) 複数のプロセスまたはスレッドによる共有リソースへの同時アクセスをコンピューターが調整するメカニズムです。
データベースでは、データは多くのユーザーによって共有されるリソースでもあります。データへの同時アクセスの一貫性と有効性をどのように確保するかは、すべてのデータベースが解決しなければならない問題であり、ロックの競合もデータベースへの同時アクセスのパフォーマンスに影響を与える重要な要素です。この観点から見ると、ロックはデータベースにとって特に重要であり、より複雑です。
1.1.2. ロックの分類
データ操作の粒度から見ると、次のようになります。
1) テーブルロック: 動作中、テーブル全体がロックされます。MyISAM 5.6 以降の InnoDB サポート
2) 行ロック: 操作中、現在の操作行はロックされます。InnoDB
データ操作のタイプから:
1) 読み取りロック (共有ロック): 同じデータに対して、複数の読み取り操作を相互に影響を与えることなく同時に実行できます。
2) 書き込みロック (排他的ロック): 現在の操作が完了する前に、他の書き込み操作と読み取り操作がブロックされます。
1.1.3. MySQL ロック
他のデータベースと比較して、MySQL のロック メカニズムは比較的シンプルであり、最も注目すべき特徴は、異なるストレージ エンジンが異なるロック メカニズムをサポートしていることです。次の表に、各ストレージ エンジンのロックのサポートを示します。
ストレージエンジン テーブルロック 行レベルのロック マイISAM サポート サポートしません InnoDB 5.6をサポート サポート これら 2 つの MySQL ロックの特徴は、次のように大まかに要約できます。
ロックタイプ 特徴 テーブルロック オーバーヘッドが低く、ロックが高速で、デッドロックがなく、ロックの粒度が大きく、ロック競合の可能性が最も高く、同時実行性が最も低い MyISAM ストレージ エンジンを推奨します。 行レベルのロック オーバーヘッドが高く、ロックが遅い InnoDB ストレージ エンジンを推奨します。デッドロックが発生します。ロックの粒度が最も小さく、ロック競合の可能性が最も低く、同時実行性も最も高くなります。 上記の特性から、一般的にどのロックが優れているかを言うのは難しいことがわかりますが、特定のアプリケーションの特性にはどのロックがより適しているかがわかります。ロックの観点からのみ: テーブル レベルのロックは、Web アプリケーションなど、インデックス条件に従って更新されるデータが少量のみのクエリベースのアプリケーションに適しており、行レベルのロックは、多数の同時実行に適しています。インデックス条件と少数の異なるデータ、および一部のオンライン トランザクション処理 (OLTP) システムなどの同時クエリ アプリケーションに基づいて更新されます。
1.2.MyISAMテーブルロック
MyISAM ストレージ エンジンはテーブル ロックのみをサポートします。これは、MySQL の最初のいくつかのバージョンでサポートされている唯一のロック タイプです。
1.2.1. テーブルロックの追加方法
MyISAM は、クエリ ステートメント (SELECT) を実行する前に、関連するすべてのテーブルに読み取りロックを自動的に追加し、更新操作 (UPDATE、DELETE、INSERT など) を実行する前に、関連するテーブルに書き込みロックを自動的に追加します。このプロセスにはユーザーの介入は必要ないため、通常、ユーザーは LOCK TABLE コマンドを使用して MyISAM テーブルを直接明示的にロックする必要はありません。ただし、効果を実証するために人為的にロックをかけています。
テーブルロック構文を表示します。
加读锁 : lock table table_name read; 加写锁 : lock table table_name write; 释放锁: unlock tables;
1.2.2. リードロックケース
環境を準備します。
create database demo_03 default charset=utf8mb4; use demo_03; CREATE TABLE `tb_book` ( `id` INT(11) auto_increment, `name` VARCHAR(50) DEFAULT NULL, `publish_time` DATE DEFAULT NULL, `status` CHAR(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=myisam DEFAULT CHARSET=utf8 ; INSERT INTO tb_book (id, name, publish_time, status) VALUES(NULL,'java编程思想','2088-08-01','1'); INSERT INTO tb_book (id, name, publish_time, status) VALUES(NULL,'solr编程思想','2088-08-08','0'); CREATE TABLE `tb_user` ( `id` INT(11) auto_increment, `name` VARCHAR(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=myisam DEFAULT CHARSET=utf8 ; INSERT INTO tb_user (id, name) VALUES(NULL,'令狐冲'); INSERT INTO tb_user (id, name) VALUES(NULL,'田伯光');
クライアント 1:
1) tb_book テーブルの読み取りロックを取得します。
lock table tb_book read;
2) クエリ操作を実行します。
select * from tb_book;
通常通り実行でき、データのクエリも可能です。
クライアント 2:
3) クエリ操作を実行します。
select * from tb_book;
クライアント 1:
4) ロックされていないテーブルのクエリ
select name from tb_user;
現在のユーザーはすでに他のテーブルをロックしているため、ロックを解除した後にのみ他のテーブルを読み取ることができます。
unlock tables;
クライアント 2: 5) ロックされていないテーブルをクエリするselect name from tb_user;
ロックされていないテーブルは通常どおりクエリできます。
クライアント 1:
6) 挿入操作を実行します
insert into tb_book values(null,'Mysql高级','2088-01-01','1');
挿入を実行してエラーを直接報告します。現在の tb_book は読み取りロックを取得しているため、更新操作を実行できません。
クライアント 2:
7) 挿入操作を実行します
insert into tb_book values(null,'Mysql高级','2088-01-01','1');
クライアント 1 でテーブルのロックを解除する lock コマンドが解放されると、クライアント 2 の inesrt ステートメントがただちに実行されます。
読み取りロック: 他のクライアントの読み取り操作には影響しませんが、他のクライアントの書き込み操作はブロックされます。
1.2.3. 書き込みロックの場合
書き込みロック(排他ロック):他のセッションに任意の操作を許可しない
クライアント 1:
1) tb_book テーブルの書き込みロックを取得します。
lock table tb_book write ;
2) クエリ操作を実行します。
select * from tb_book ;
クエリ操作は正常に実行されました。
3) アップデート操作を実行する
update tb_book set name = 'java编程思想(第二版)' where id = 1;
更新操作は正常に実行されました。
クライアント 2:
4) クエリ操作を実行します。
select * from tb_book ;
クライアント 1 でテーブルのロックを解除する lock コマンドが解放されると、クライアント 2 の select ステートメントがすぐに実行されます。
書き込みロック: 他のユーザーの操作をブロックします。
要約する
1.3. InnoDB 行ロックはトランザクションをサポートします
1.3.1. 行ロックの概要
行ロックの特徴: InnoDB ストレージ エンジンに偏り、オーバーヘッドが高く、ロックが遅い、デッドロックが発生する可能性がある、ロックの粒度が最も小さく、ロック競合の可能性が最も低く、同時実行性の度合いも最も高い。
InnoDB と MyISAM の間には 2 つの大きな違いがあります: 1 つはトランザクションをサポートすること、もう 1 つは行レベルのロックを使用することです。
1.3.2. 背景知識
どのようなビジネス?
トランザクションはアプリケーション内の一貫した一連の操作であり、すべての操作が正常に完了する必要があります。正常に完了しないと、各操作中に行われたすべての変更が元に戻されます。つまり、トランザクションはアトミックであり、トランザクション内の一連の操作は成功するか、何も実行されないかのどちらかです。トランザクションとその ACID プロパティ
トランザクションは、一連の SQL ステートメントで構成される論理処理単位です。
トランザクションには、トランザクション ACID プロパティと呼ばれる次の 4 つの特性があります。
ACIDのプロパティ 意味 原子性 トランザクションはアトミックな操作単位であり、データへの変更は成功するか失敗します。 一貫性のある データは、トランザクションの開始時と終了時の両方で一貫した状態にある必要があります。 分離 データベース システムは、トランザクションが外部の同時操作の影響を受けない「独立した」環境で実行されることを保証するための特定の分離メカニズムを提供します。 耐久性のある トランザクションが完了すると、データへの変更は永続的になります。 トランザクションの同時処理によって引き起こされる問題
質問 意味 失われたアップデート 2 つ以上のトランザクションが同じ行を選択すると、最初のトランザクションによって変更された値は、後続のトランザクションによって変更された値によって上書きされます。 ダーティリード トランザクションがデータにアクセスしてデータを変更しているが、その変更がデータベースに送信されていない場合、この時点で別のトランザクションもデータにアクセスし、そのデータを使用します。 反復不可能な読み取り (反復不可能な読み取り) トランザクションは、あるデータを読み込んだ後、ある時点で以前に読み取ったデータを読み込みますが、以前に読み込んだデータと不一致であることがわかります。 ファントムリード トランザクションは、同じクエリ条件に従って以前にクエリされたデータを再読み取りしますが、他のトランザクションがそのクエリ条件を満たす新しいデータを挿入したことがわかります。 トランザクション分離レベル
前述のトランザクションの同時実行性の問題を解決するために、データベースはこの問題を解決するための特定のトランザクション分離メカニズムを提供します。データベースのトランザクション分離が厳格であればあるほど、同時実行性の副作用は小さくなりますが、支払う代償は大きくなります。これは、トランザクション分離は本質的にトランザクションをある程度まで「シリアル化」することであり、これは明らかに「同時実行性」と矛盾するためです。
データベースには低から高まで、read uncommitted、read commit、Repeatable Read、serializable の 4 つの分離レベルがあり、これら 4 つのレベルにより、ダーティ ライト、ダーティ リード、非繰り返し読み取り、ファントム リードなどの問題を 1 つずつ解決できます。 。
分離レベル 失われたアップデート ダーティリード 反復不可能な読み取り ファントムリーディング コミットされていない読み取り × √ √ √ 読み取りがコミットされました × × √ √ 反復可能な読み取り (デフォルト) × × × √ シリアル化可能 × × × × 備考:○は出現する可能性がある、×は出現しないことを示す。
Mysql データベースのデフォルトの分離レベルは、Repeatable read、view メソッドです。
show variables like 'tx_isolation';
1.3.3. InnoDB の行ロック モード
InnoDB は、次の 2 種類の行ロックを実装します。
共有ロック (S): 読み取りロック、または短縮して S ロックとも呼ばれる共有ロックは、複数のトランザクションが同じデータのロックを共有でき、すべてのトランザクションがデータにアクセスできることを意味しますが、読み取りのみが可能で、データにはアクセスできません。変更される。
select を実行すると、innodb はデフォルトでデータベースに共有ロックを追加します。
排他的ロック (X): 書き込みロック、略して X ロックとも呼ばれます。排他的ロックは他のロックと共存できません。たとえば、トランザクションがデータ行の排他ロックを取得すると、他のトランザクションはデータ行の他のロックを取得できなくなります。行には共有ロックと排他ロックが含まれますが、排他ロックを取得するトランザクションはデータの読み取りと変更が可能です。
変更操作を実行すると、デフォルトで InnoDB はデータベース テーブル内の対応する行に排他ロックを追加します。
UPDATE、DELETE、INSERT ステートメントの場合、InnoDB は関連するデータ セットに排他ロック (X) を自動的に追加します。
通常の SELECT ステートメントの場合、InnoDB はロックを追加しません。
1.3.4. ケースの準備 innodb はトランザクションの行レベルのロックをサポートします
create table test_innodb_lock( id int(11), name varchar(16), sex varchar(1) )engine = innodb default charset=utf8; insert into test_innodb_lock values(1,'100','1'); insert into test_innodb_lock values(3,'3','1'); insert into test_innodb_lock values(4,'400','0'); insert into test_innodb_lock values(5,'500','1'); insert into test_innodb_lock values(6,'600','0'); insert into test_innodb_lock values(7,'700','0'); insert into test_innodb_lock values(8,'800','1'); insert into test_innodb_lock values(9,'900','1'); insert into test_innodb_lock values(1,'200','0'); create index idx_test_innodb_lock_id on test_innodb_lock(id); create index idx_test_innodb_lock_name on test_innodb_lock(name);
1.3.5. 行ロックの基本的なデモ - トランザクションのサポート
セッション-1 セッション-2 自動コミットをオフにする
自動コミットをオフにする
すべてのデータを正常にクエリできます
すべてのデータを正常にクエリできます
ID 3 のデータをクエリする
ID 3 のデータを取得します
ID 3 でデータを更新しますが、送信はしません。
ID 3 のデータを待機状態で更新します
commit を通じてトランザクションを送信する
ブロックを解除すると、アップデートは正常に進行します
上では、同じ行のデータが操作され、次に、異なる行のデータが示されます。
これはセッション 1 操作と同じ行ではないため、現在の行ロックを取得して更新を実行します。idが3のデータを更新し、行ロックを正常に取得して更新を実行します。 行レベル:
分割されます: 共有ロック: このロックは、選択が実行されると自動的に追加されます。他の操作には影響しません。
排他的ロック: このロックは、更新操作が実行されると自動的に追加されます。他のトランザクションに影響を与える更新操作
1.4. 悲観的ロックと楽観的ロック
- 楽観的ロック: データを取得しに行くたびに、他の人がデータを変更しないと考えてロックされませんが、更新を送信するときに、この期間中に他の人がデータを更新したかどうかを判断します。
- 悲観的ロック: データを取得しに行くたびに、他の人がデータを変更するだろうと考えるため、データを取得するたびにデータをロックし、他の人がデータを取得しようとしてもロックが解除されるまで停止するようにします。 。
- データベースのオプティミスティック ロックは自分で実装する必要があります。テーブルにバージョン フィールドを追加し、各変更の成功値に 1 を追加します。これにより、データベースを変更するたびに、所有しているバージョンが一致しているかどうかが最初に比較されます。データベースの現在のバージョン。オプティミスティック ロックが実装されるように変更します。