1分ポジショニングネクストキーロック、あなたは数分かかります
タグ:MySQLの、ネクストキーロック、意図的ロック挿入
接続スレッド
表示接続情報 show processlist
+----+------+------------------+------+---------+------+----------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+------------------+------+---------+------+----------+------------------+
| 3 | root | 172.17.0.1:60542 | test | Query | 0 | starting | show processlist |
| 5 | root | 172.17.0.1:60546 | test | Sleep | 4168 | | <null> |
| 8 | root | 172.17.0.1:60552 | test | Sleep | 4170 | | <null> |
+----+------+------------------+------+---------+------+----------+------------------+
スレッドへのリンクだけmysqlの非エンタープライズ版のサポート
ビューのスレッドモデル show variables like 'thread_handling'
+-----------------------------------------+---------------------------+
| Variable_name | Value |
+-----------------------------------------+---------------------------+
| thread_handling | one-thread-per-connection |
+-----------------------------------------+---------------------------+
[取引戦略をコミット]
ノートへの時点を2つの隠されたトランザクションをコミットしている、1つ目はautocommit=1
MySQLのセッションレベルの変数が自動的にすべての提出ORMのデフォルトで自動的に提出されるトランザクションがコミット制御現在の文の枠組みの中で、この電界の影響を受けていますそれが表示されている場合は、トランザクションが開始し、自分の業務には、マニュアルの提出を必要と開きます。ときどきORMフレームワークはいくつかの設定や戦略に基づいて行われます、自動コミットは 0に設定されています。
第二は、かつてのDDL操作は、現在のトランザクションを暗黙的にコミットすることで、いくつかの混合DMLとDDLスクリプトを併用し、その一貫性があるでしょう。DDLは、自動的に現在のトランザクションをコミットします。DDLので5.7より前では、トランザクションの動作原理をサポートしていません。(Mysql8.0はすでにトランザクションのDDLをサポートしています)
ネクストキーロックの調査
ネクストキーロックのみで起こるRR(REPEATABLE-READ)分離レベルで。
MySQLはロックの種の多くの種類があり、表锁
、、 、record lock
、gap lock
、意向共享/排他锁
、、插入意向锁
除外されたメタデータロックは、ロックの組み合わせの残りの後Auto_Incr増分ロックは、次の最もRR分離レベルです。元数据锁
Auto_Incr自增锁
RR分離レベルは、RR分離レベルのトランザクションの最大スループットの下では、MySQLの強みの一つであり、デフォルトのトランザクション分離レベルで、そしてファントム読み取り問題は表示されません。ネクストキーロックは、この問題を解決することであり、それは単に、レコードロック+ギャップロックがあるネクストキーロック。
_読むには_マジック根本的な問題は、そのような私たちの統計よりも30歳年上の数として、記録された値の境界で発見された:select count(1) peoples where age>30
この文は、各クエリの結果セットのために取得する可能性があり、彼らが会うので、同じではありません> 30歳のを私たちにレコードの人々のテーブルでは、クエリをヒットします。
だから、我々は間隔が大きくなり、変更されたかのように2つのレコードの前と後、二回修正された記録ギャップがレコードに挿入されるが、記録を阻止することはできません読んでいないだけでファントムを解決するために必要な、ファントム読み込みが発生するがあるでしょう。
ここでは、例を見てみましょう。
CREATE TABLE `peoples` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_peoples_age` (`age`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4
+----+-----+
| id | age |
+----+-----+
| 1 | 20 |
| 2 | 30 |
| 3 | 35 |
| 4 | 40 |
+----+-----+
デバッグを容易にするために、InnoDBは、ロック・タイムアウト・転送大きい点を取得します
show variables like '%innodb_lock_wait%'
set innodb_lock_wait_timeout=600
二つのセッションを開きます。
session A id=8:
begin
select count(1) from peoples where age>30 for update;
session B id=5:
begin
insert into peoples(age) values(31)
show processlist
Idは接続を見つけます。
***************************[ 1. row ]***************************
Id | 3
User | root
Host | 172.17.0.1:60542
db | test
Command | Query
Time | 0
State | starting
Info | show processlist
***************************[ 2. row ]***************************
Id | 5
User | root
Host | 172.17.0.1:60546
db | test
Command | Query
Time | 394
State | update
Info | insert into peoples(age) values(31)
***************************[ 3. row ]***************************
Id | 8
User | root
Host | 172.17.0.1:60552
db | test
Command | Sleep
Time | 396
State |
Info | <null>
- 業務
select * from information_schema.innodb_trx \G
トランザクションの実装を確認してください。
***************************[ 1. row ]***************************
trx_id | 457240
trx_state | LOCK WAIT
trx_started | 2020-01-27 06:08:12
trx_requested_lock_id | 457240:131:4:4
trx_wait_started | 2020-01-27 06:09:25
trx_weight | 6
trx_mysql_thread_id | 5
trx_query | insert into peoples(age) values(31)
trx_operation_state | inserting
trx_tables_in_use | 1
trx_tables_locked | 1
trx_lock_structs | 5
trx_lock_memory_bytes | 1136
trx_rows_locked | 4
trx_rows_modified | 1
trx_concurrency_tickets | 0
trx_isolation_level | REPEATABLE READ
trx_unique_checks | 1
trx_foreign_key_checks | 1
trx_last_foreign_key_error | <null>
trx_adaptive_hash_latched | 0
trx_adaptive_hash_timeout | 0
trx_is_read_only | 0
trx_autocommit_non_locking | 0
***************************[ 2. row ]***************************
trx_id | 457239
trx_state | RUNNING
trx_started | 2020-01-27 06:07:59
trx_requested_lock_id | <null>
trx_wait_started | <null>
trx_weight | 3
trx_mysql_thread_id | 8
trx_query | <null>
trx_operation_state | <null>
trx_tables_in_use | 0
trx_tables_locked | 1
trx_lock_structs | 3
trx_lock_memory_bytes | 1136
trx_rows_locked | 5
trx_rows_modified | 0
trx_concurrency_tickets | 0
trx_isolation_level | REPEATABLE READ
trx_unique_checks | 1
trx_foreign_key_checks | 1
trx_last_foreign_key_error | <null>
trx_adaptive_hash_latched | 0
trx_adaptive_hash_timeout | 0
trx_is_read_only | 0
trx_autocommit_non_locking | 0
457240トランザクションの状態がされLOCK WAIT
たロックを待って、事務の457239状態はRUNNING
、実行、我々は、トランザクションのコミットを待っています。
- ロック
select * from information_schema.innodb_locks \G
占有ロックを表示します。
***************************[ 1. row ]***************************
lock_id | 457240:131:4:4
lock_trx_id | 457240
lock_mode | X,GAP
lock_type | RECORD
lock_table | `test`.`peoples`
lock_index | idx_peoples_age
lock_space | 131
lock_page | 4
lock_rec | 4
lock_data | 35, 7
***************************[ 2. row ]***************************
lock_id | 457239:131:4:4
lock_trx_id | 457239
lock_mode | X
lock_type | RECORD
lock_table | `test`.`peoples`
lock_index | idx_peoples_age
lock_space | 131
lock_page | 4
lock_rec | 4
lock_data | 35, 7
innodb_locksテーブルには、すでにロック要求とロック情報を取得した情報が含まれています。lock_indexフィールドはインデックスを行くためにロックを示し、記録ロックは、インデックス作成が完了しております。
トランザクションの状態は、ロック取得する457240以上であるlock_data | 35, 7
、要求されたデータ表現を。トランザクションは現在、457239 Xロックで占められています。
- ロック待機
select * from information_schema.innodb_lock_waits
ロック待機情報を確認してください。
***************************[ 1. row ]***************************
requesting_trx_id | 457240
requested_lock_id | 457240:131:4:4
blocking_trx_id | 457239
blocking_lock_id | 457239:131:4:4
457240のトランザクションが131を取得する必要があります:4:4:4:4錠4錠を、131の457の239のサービスを占めていました。
- InnoDBのモニター
show engine innodb status
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 422032240994144, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 457240, ACTIVE 394 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 7 row lock(s), undo log entries 1
MySQL thread id 5, OS thread handle 140556966967040, query id 105 172.17.0.1 root update
insert into peoples(age) values(31)
------- TRX HAS BEEN WAITING 165 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 131 page no 4 n bits 72 index idx_peoples_age of table `test`.`peoples` trx id 457240 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 80000023; asc #;;
1: len 4; hex 00000007; asc ;;
------------------
---TRANSACTION 457239, ACTIVE 407 sec
3 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 8, OS thread handle 140556966696704, query id 104 172.17.0.1 root
MySQLのスレッドID 5は、インサートインテントロックに準備されている插入意向锁
本質的に相互に排他的ではないに最大同時挿入、無関係な行を確保するために、プラスギャップをロックします。スレッドID 5プラスギャップロックを挿入する前に、主な問題は一貫性であることを確認する必要が同時挿入を防止しました。
セッション5、およびセッション8が= 35レコードID = 3、年齢に動作していないが、X +ギャップロックは、ファントム読み取りの問題を解決する唯一の方法がロックされていました。
著者:王Qingpei(楽しい見出しテックリーダー)