(I.概要
複数のスレッドによって同時に操作される可能性のあるリソースを重要なリソースと呼びます。ロックの目的は、1つのスレッドだけがこれらの重要なリソースに同時にアクセスできるようにすることです。これは、当時同期ロックについて語ったときに提唱されたロックの概念です。
ユーザーが共有するリソースとして、データの同時アクセスの一貫性を確保する方法も、すべてのデータベースが解決しなければならない問題です。ロックの方法は、データベースの同時アクセスのパフォーマンスにおける重要な要素です。
(B)データベースロックについて
ロック形式から、楽観的ロックと悲観的ロックに分けられます
データベース操作の種類から、読み取りロック(共有ロック)と書き込みロック(排他ロック)に分けられます。
読み取りロック:複数の読み取り操作を相互に影響を与えることなく同時に実行できます。
書き込みロック:現在の書き込み操作が完了する前に、他の読み取りロックと書き込みロックは除外されます。
データ操作の粒度から、テーブルロックと行ロックに分けることができます
2.1テーブルロック
名前が示すように、テーブルロックはテーブル全体をロックすることです。この種の操作は、オーバーヘッドが低く、ロックが高速で、デッドロックがありませんが、ロックの粒度が大きく、同時実行性が低くなります。MyISAMエンジンは、データの操作時にデータにテーブルロックを自動的に追加します。
次のパラメータを使用して、テーブルロックを手動で増やすことができます。
lock table 表名 read(write)
- 1
テーブルに追加されたロックを表示します。
show open tables;
- 1
ロックを解除します。
unlock tables;
読み取りロックが追加されると、書き込みが制限されます。書き込みロックが追加されると、読み取りと書き込みが制限されます。
2.2行ロック
行ロックは、データの行をロックすることです。この方法は、コストがかかり、ロックに時間がかかり、デッドロックが発生します。ただし、ロックの粒度は小さく、同時実行性は最も高くなります。InnoDBは行ロックをサポートしますが、InnoDBはトランザクションもサポートします。
簡単な例で行ロックを導入するために、2つのセッションを開いて(Navicatでは2つのクエリウィンドウを開きます)、データベースを操作します。データベースでは、最初のクエリでデータが変更されますが、送信されません。
begin;
update test_innodb set name='javayz2' where id=1;
このとき、別のクエリウィンドウを使用して、同じデータ行を変更します。
update test_innodb set name='javayz3' where id=1;
現時点では、この更新ステートメントの行は永久にブロックされます。最初のクエリで変更されたデータを送信します。
commit
2番目のクエリの変更もすぐに有効に
なります。結果を表示し、30秒間ブロックします。
注:InnoDBの行ロックがインデックスに追加されます。インデックスに障害が発生した場合、またはインデックス付けされていないフィールドが変更された場合、行ロックはテーブルロックにアップグレードされます。
(3)Mysqlトランザクション分離レベル
トランザクション分離レベルについて説明する前に、次の概念を知っておく必要があります。
トランザクションのACIDプロパティ:原子性、一貫性、分離、および耐久性。
同時実行によって引き起こされる可能性のある問題:更新の欠落、ダーティリード、反復不可能なリード、およびファントムリード。
更新の損失:つまり、複数のトランザクションが同時にデータの行を更新し、最後の更新が前のトランザクションの更新をカバーするようにします。
ダーティ読み取り:トランザクションAは、トランザクションBの変更されたがコミットされていないデータを読み取ります。
繰り返し不可の読み取り:つまり、トランザクションAは一部のデータを読み取り、次にデータを読み取り、データが変更されたことを検出します。トランザクションAは、他のトランザクションによって送信されたデータを読み取るため、分離を満たしていません。
ファントム読み取り:つまり、トランザクションAがいくつかのデータを読み取り、同じ条件でそれを読み取った後、新しいデータがさらにあることがわかります。これは、トランザクションAが他のトランザクションの新しいデータを読み取るためであり、分離を満たしていません。
上記の概念を理解すると、Mysqlのトランザクション分離レベルを知ることができます。以下の表の形式で示されている4つのトランザクション分離レベルがあります。
分離レベル | ダーティリード | 繰り返し不可 | ファントムリーディング |
---|---|---|---|
コミットされていない読み取り(コミットされていない読み取り) | √ | √ | √ |
読み取りが送信されました(読み取りコミット済み) | ×× | √ | √ |
繰り返し可能-読む | ×× | ×× | √ |
シリアル化可能 | ×× | ×× | ×× |
分離レベルが厳密であるほど、並行性によって引き起こされる問題は小さくなりますが、並行性の程度は低くなります。
Mysqlのデフォルトのトランザクション分離レベルは繰り返し可能な読み取りです。次のステートメントで表示できます
show VARIABLES like 'tx_isolation'
次のステートメントを使用して、トランザクション分離レベルを変更します。
set tx_isolation='READ-COMMITTED'
//READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE
(4)MVCCメカニズム
トランザクション分離レベルが反復可能読み取りに設定されている場合、トランザクションAがselectを実行した後、トランザクションBがデータを変更すると、トランザクションAのselectが最後のデータになりますが、挿入、更新、および削除が使用される場合、使用されるデータは次のようになります。トランザクションBの変更されたデータですか、
たとえば、トランザクションAの最初のクエリは23であり、トランザクションBは年齢に1を追加し、トランザクションAの2番目のクエリはまだ23です。トランザクションAが年齢に1を追加する場合、クエリは25です。
反復可能な分離レベルは、MVCC(Multi-Version Concurrency Control)メカニズムを使用しますが、その実装メカニズムはより複雑です。後で説明する特別な記事を投稿します。彼が達成した目的は、選択操作が過去のスナップショットバージョンを読み取り、挿入、更新、および削除して最新バージョンを更新することです。
(5)繰り返し読み取りの場合のファントム読み取りの問題を解決する方法
Mysqlのデフォルトのトランザクション分離レベルは繰り返し可能な読み取りですが、ファントム読み取りの問題は解決されません。シリアル化可能に変更された場合、同時実行性が低すぎるため、繰り返し可能な読み取りの場合にファントム読み取りの問題を解決できるかどうかインタビューにもあります。もっと頻繁に会いました。
解決策は、ギャップロックを使用することです。トランザクションの1つで更新ステートメントが実行されたら、次のような範囲を追加します。
update test_innodb set name='javayz3' where id>1 and id<10
IDが1〜10のデータは、他のトランザクションで挿入または変更することはできず、当然、ファントムの読み取りは行われません。
(6)デッドロックについて
プロジェクトでは、デッドロックが発生することがあります。デッドロックは実際には非常に単純です。SessionAはsessionBの完了を待機し、sessionBはsessionAの完了を待機して、無限のループを形成します。たとえば、次の更新ステートメント:
A:begin;
update test_innodb set name='aa' where id=1; //锁住id为1的行
B:begin;
update test_innodb set name='bb' where id=2; //锁住id为2的行
A:update test_innodb set name='aa' where id=2;
B:update test_innodb set name='bb' where id=1;
最終的に、AはBによってブロックされ、BはAによってブロックされ、デッドロックが発生します。
Mysqlにデッドロック処理メカニズムが追加されました。デッドロックの場合、ロールバックによってロックが解除されますが、複雑なデッドロックが発生したときにロックを解除できない場合があります。
(7)まとめ
記事全体で最初にMysqlロックについて説明し、Myisamはテーブルロックを使用し、InnoDBは行ロックを使用します。次に、トランザクションの基本原則を紹介し、それによってMysqlのトランザクション分離レベルを引き出しました。MVCCメカニズムを簡単に紹介し、次にギャップロックとデッドロックについて説明します。これらを習得すると、職場や面接中にMysqlの問題を解決するためのアイデアが得られます。さて、これでこの号の内容はすべてです。またお会いしましょう!