今日のインターネットでは、データベースなしでは大規模なマルチプレイヤー APP を開発できません。誰もが高い同時実行性で読み書きできることを保証する方法は、常に難しいアーキテクチャ上の問題でした。まず第一に、高い同時実行性が排除され、一貫した読み書きを保証するために最も一般的に使用される方法はトランザクションであり、実装の重要なポイントです。トランザクションがロックされているメカニズム。
今日は、一貫した読み取りと書き込みを実現するために、InnoDB ストレージ エンジンが高い同時実行性の下でロック メカニズムを実装する方法の原理と実装を紹介します。
ロック
データベースのロック メカニズムは、データベースをファイル システムと区別する重要な機能です。共有リソースへの同時アクセスを管理するために使用されます。 InnoDB は、操作データ テーブル、LRU ページ リスト、バッファ プール内のデータ行など、多くの場所でロック メカニズムを使用しており、一貫性と整合性を確保するには、ロック メカニズムが必要です。
データベースが異なると、ロック メカニズムの設計と実装は完全に異なります。
##MyISAM エンジン: テーブル ロックの設計、同時読み取りは問題ありませんが、同時書き込みのパフォーマンスは劣ります。#●Microsoft SQL Server: オプティミスティック同時実行とペシミスティック同時実行をサポートします。オプティミスティック同時実行は行レベルのロックをサポートします。ロックの維持にはコストがかかります。行ロックの数がしきい値を超えると、テーブル ロックにアップグレードされます。
#●InnoDB エンジン: 行ロックをサポートし、一貫した非ロック読み取りを提供します。行ロックには追加のオーバーヘッドはなく、パフォーマンスも低下しません。#●Oracle: InnoDB エンジンに非常に似ています。
2 種類のロック: ロックとラッチ
データベースでは、ロックとラッチの両方をロックと呼ぶことができますが、大きな違いがあります。違い。 ラッチは一般にラッチと呼ばれ、同時スレッドによる重要なリソース操作の正確性を保証するために使用されます。オブジェクトはメモリ データ構造です。ロック時間は非常に短くする必要があり、デッドロックは発生しません。検出されました。 InnoDB エンジンでは、mutex (ミューテックス) と rwlock (読み取り/書き込みロック) に分けられます。
Lock は、データベース内のテーブル、ページ、行などのオブジェクトをロックするために使用されます。対象はトランザクションです。コミット/ロールバック後に解放され、デッドロックが検出されます。行ロック、テーブル ロック、インテント ロックに分かれています。
下記の錠前は錠前タイプの錠前を指します。
4 つのロック タイプ
InnoDB は 4 つのロックをサポートします: # 共有ロック (S ロック): トランザクションを許可します。データ行
##●排他的ロック (X ロック): トランザクションによるデータ行の削除または更新を許可します##●意図 S ロック: トランザクションはテーブル内の特定の行を取得しようとします。ロック
#意図 X ロック: トランザクションはテーブル内の特定の行の排他ロックを取得しようとしています
#トランザクション T1 が行の共有ロックを取得すると、行データは変更されないため、トランザクション T2 は、行 r の共有ロックを直接取得することもできます。これをロック互換と呼びます。
トランザクション T3 がデータを変更するために行 r の排他ロックを取得したい場合、T1/T2 が行共有ロックを解放するまで待つ必要があります。これはロックの非互換性と呼ばれます。
S ロックと X ロックはどちらも行ロックですが、IS ロックと IX ロックは意図的なロックであり、テーブル ロックに属します。インテンション ロックは、トランザクション内の次の行に要求されるロックのタイプを明らかにするように設計されています。つまり、テーブル ロックのより細かい粒度でロックします。 InnoDB はテーブル ロックをサポートしているため、インテント ロックはテーブル全体のスキャン以外のリクエストをブロックしません。
ロックの互換性:
#ISS |
#IS | 互換性あり | 互換性あり | |
互換性なし | IX | 互換性あり | 互換性あり | |
互換性なし | S | 互換性あり | 互換性なし | |
##XX | 互換性なし | 非互換 | 非互換 | |
ストレージ トランザクションおよびロック情報の 3 つのテーブル |
InnoDB1.0 以降、INNODB_TRX (トランザクション テーブル)、INNODB_LOCKS (ロック テーブル)、INNODB_LOCK_WAITS (ロック待機テーブル) が INFORMATION_SCHEMA アーキテクチャの下に追加され、これら 3 つのテーブルを通じて、現在の状況を監視できます。リアルタイムでトランザクションを分析し、考えられるテーブルの問題を分析します。 3 つのテーブルの定義は次のとおりです:
INNODB_TRX
##trx_id
trx_state | 現在のトランザクションのステータス||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
trx_started | トランザクションの開始時刻 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
trx_requested_lock_id | トランザクションを待機しているロック IDC。ステータスが LOCK WAIT でない場合は、 NULL | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
trx_wait_started | トランザクションの開始を待機する時間 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
trx_weight | トランザクションの重みトランザクションは、トランザクションによって変更およびロックされた行の数を反映します。ロールバックが必要な場合は、ロールバックの値が最も小さいトランザクションを選択します。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
trx_mysql_thread_id | MySQL のスレッド ID、show processlist で表示される結果 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
trx_query | トランザクション操作の SQL ステートメント | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
#INNODB_LOCKS
| |
---|---|
lockID | lock_trx_idトランザクション ID |
lock_mode | ロック モード |
lock_type | ロックのタイプ、テーブル ロックまたは行ロック |
lock_table | ロック対象のテーブル |
lock_index | ロックされたインデックス |
#lock_space | #ロック オブジェクトのスペース ID|
ロック オブジェクトの数トランザクション ロックされたページ、テーブルがロックされている場合は NULL | #lock_rec |
#lock_data | |
#INNODB_LOCK_WAITS |
requesting_lock_id | 適用 ロックの ID|
---|---|
blocking_trx_id | ブロックするトランザクション ID |
blocking_lock_id | ブロッキング ロック ID |
INNODB_TRX | |
INNODB_LOCKS | を通じてすべてのロック情報を表示します。その後、 | INNODB_LOCK_WAITS
#分離レベル
まず、データベースの 4 つのトランザクション分離レベルについて説明します。 UNCOMMITTED (0 ): ブラウズ アクセス レベル、ダーティ読み取り、非反復読み取り、およびファントム読み取りがあります。#●READ COMMITTED(1): カーソル安定性レベル、非反復読み取り、ファントム読み取りがあります
これら 4 つのトランザクション分離InnoDB のデフォルトの分離レベルは REAPEATABLE READ ですが、他のデータベースとは異なり、ファントム リードの発生を回避できる Next-Key-Lock ロック アルゴリズムも使用するため、SQL 標準のレベルを完全に満たすことができます。トランザクション分離要件、つまり、SERIALIZABLE 分離レベルを達成できます。 分離レベルが低いほど、トランザクションによって要求されるロックが少なくなるか、ロックの保持時間が短くなるため、ほとんどのデータベースのデフォルトの分離レベルは READ COMMITED になります。ただし、関連する分析では、分離レベルのパフォーマンスのオーバーヘッドはほぼ同じであるため、ユーザーがパフォーマンスを向上させるために分離レベルを調整する必要がないことも指摘しています。
トランザクション分離レベルを表示および変更するコマンド:mysql> select @@session.tx_isolation; +------------------------+ | @@session.tx_isolation | +------------------------+ | REPEATABLE-READ | +------------------------+ 1 row in set (0.00 sec) mysql> set session transaction isolation level SERIALIZABLE; Query OK, 0 rows affected (0.00 sec)
[mysqld] transaction-isolation = READ-COMMITED
#● READ COMMITED: 常に最新のスナップショットを読み取ります
● REPEATABLE READ: トランザクションの開始時に常に行データのバージョンを読み取ります。
例を実行します。
##一貫した非ロック読み取り
Timeセッション Aセッション BBEGIN
| ||
---|---|---|
2 | select * from z where a = 3; | |
3 | ||
4 | ||
5 |
select * from z where a = 3 ; |
|
6 | ||
選択* z から、a = 3; | ||
COMMIT; | ## 在这个例子中我们可以清晰的看到0、1、2三种隔离级别的区别: #在事务开始前我们可以分别调整为0、1、2三种隔离级别,来查看不同的输出 mysql> set session transaction isolation level READ UNCOMMITTED; Query OK, 0 rows affected (0.00 sec) mysql> select @@tx_isolation; +------------------+ | @@tx_isolation | +------------------+ | READ-UNCOMMITTED | +------------------+ 1 row in set (0.00 sec) # A会话:T1事务 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from z where a = 3; +---+------+ | a | b | +---+------+ | 3 | 1 | +---+------+ 1 row in set (0.00 sec) # B会话:T2事务 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update z set b=2 where a=3; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 # A会话:T1事务,如果此时隔离级别是READ-UNCOMMITTED,因为此刻事务2可能会回滚,所以出现了脏读 mysql> select * from z where a=3; +---+------+ | a | b | +---+------+ | 3 | 2 | +---+------+ 1 row in set (0.00 sec) # A会话:T1事务,如果此时隔离级别是大于READ-UNCOMMITTED的更高级别 mysql> select * from z where a=3; +---+------+ | a | b | +---+------+ | 3 | 1 | +---+------+ 1 row in set (0.00 sec) # B会话:T2事务 mysql> commit; Query OK, 0 rows affected (0.00 sec) # A会话:T1事务,如果此时隔离级别是READ-COMMITTED,因为数据和事务开始时读取的出现了不一致,因此称为不可重复读,能够读到其他事务的结果,违反了事务的隔离性 mysql> select * from z where a=3; +---+------+ | a | b | +---+------+ | 3 | 2 | +---+------+ 1 row in set (0.00 sec) # A会话:T1事务,如果此时隔离级别是大于READ-COMMITTED的更高级别 mysql> select * from z where a=3; +---+------+ | a | b | +---+------+ | 3 | 1 | +---+------+ 1 row in set (0.00 sec) # A会话:T1事务 mysql> commit; Query OK, 0 rows affected (0.00 sec) ログイン後にコピー 一致性锁定读和SERIALIZABLE隔离 在默认的REPEATABLE READ隔离级别时,InnoDB使用的是一致性非锁定读。但有时我们也需要显示的指定使用一致性锁定读来保证读取操作时对数据进行加锁达到一致性。这要求数据库支持锁定读加锁语句: ● select ... for update: 读取时对行记录加X锁 ● select ... lock in share mode:读取时对行记录加一个S锁 这两种锁必须在一个事务中,当事务提交后锁也就释放了,因此务必加上BEGIN, START TRANSACTION或者SET AUTOCOMMIT=0。 我们在前面隔离级别时也说过SERIALIZABLE隔离级别会对读操作自动加上LOCK IN SHARE MODE指令来加上一个共享锁,因此不再支持一致性的非锁定读。这也是隔离级别3的一大特性。 总结 由于锁的概念非常重要,这里先讲了锁的概念、锁的类型、锁的信息查看、事务的隔离级别和区别,后面我们会继续说锁的算法、锁的三种问题和幻读、死锁和锁升级。 推荐学习:MySQL教程 |
以上がMySQL ロックとトランザクション分離レベル (概要)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。