MySQL 5.7.26
表 a 中的字段 b_id 外键关联 表 b 中的 id
- create table a
- (
- id int auto_increment
- primary key,
- name varchar(64) null,
- age int null,
- b_id int null,
- constraint a_b_id_fk
- foreign key (b_id) references b (id)
- );
- [
- {
- "id": 2,
- "name": "hsh",
- "age": 24,
- "b_id": 3
- }
- ]
- create table b
- (
- id int auto_increment
- primary key,
- name varchar(64) null,
- time bigint null
- );
- [
- {
- "id": 3,
- "name": "h",
- "time": 330
- }
- ]
通过主、外键更新数据来产生排它锁,阻塞和死锁。
步骤 | 事务1 id=56389 | 事务2 id=56390 |
1 | update a set name='hsh_1' where id = 2; | |
2 | update a set age=19 where b_id = 3; | |
3 | update a set name='hsh_2' where b_id = 3; |
当执行完第2步时,事务2阻塞,此时事务与锁的状态为:
- select *
- from information_schema.INNODB_TRX trx
- left join information_schema.INNODB_LOCKS locks on trx.trx_id = locks.lock_trx_id;
- [
- {
- "trx_id": "56389",
- "trx_state": "RUNNING",
- "trx_started": "2022-08-20 16:07:43",
- "trx_requested_lock_id": null,
- "trx_wait_started": null,
- "trx_weight": 3,
- "trx_mysql_thread_id": 12,
- "trx_query": null,
- "trx_operation_state": null,
- "trx_tables_in_use": 0,
- "trx_tables_locked": 1,
- "trx_lock_structs": 2,
- "trx_lock_memory_bytes": 1136,
- "trx_rows_locked": 1,
- "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,
- "lock_id": "56389:227:3:9",
- "lock_trx_id": "56389",
- "lock_mode": "X",
- "lock_type": "RECORD",
- "lock_table": "`dps`.`a`",
- "lock_index": "PRIMARY",
- "lock_space": 227,
- "lock_page": 3,
- "lock_rec": 9,
- "lock_data": "2"
- },
- {
- "trx_id": "56390",
- "trx_state": "LOCK WAIT",
- "trx_started": "2022-08-20 16:07:55",
- "trx_requested_lock_id": "56390:227:3:9",
- "trx_wait_started": "2022-08-20 16:07:55",
- "trx_weight": 3,
- "trx_mysql_thread_id": 13,
- "trx_query": "/* ApplicationName=DataGrip 2022.2 */ update a set age=19 where b_id=3",
- "trx_operation_state": "starting index read",
- "trx_tables_in_use": 1,
- "trx_tables_locked": 1,
- "trx_lock_structs": 3,
- "trx_lock_memory_bytes": 1136,
- "trx_rows_locked": 2,
- "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,
- "lock_id": "56390:227:3:9",
- "lock_trx_id": "56390",
- "lock_mode": "X",
- "lock_type": "RECORD",
- "lock_table": "`dps`.`a`",
- "lock_index": "PRIMARY",
- "lock_space": 227,
- "lock_page": 3,
- "lock_rec": 9,
- "lock_data": "2"
- }
- ]
- select * from information_schema.INNODB_LOCK_WAITS;
- [
- {
- "requesting_trx_id": "56390",
- "requested_lock_id": "56390:227:3:9",
- "blocking_trx_id": "56389",
- "blocking_lock_id": "56389:227:3:9"
- }
- ]
可以看出事务2当前处于锁等待状态,也就是阻塞状态。事务2当前正在请求的锁id为 56390:227:3:9。
事务1对应的锁ID为56389:227:3:9,这两个其实是同一把锁,都是添加在 表空间为227页号为3行记录是9的行上,是加在主键索引上。
再执行步骤3,产生死锁,事务2被kill掉。
[40001][1213] Deadlock found when trying to get lock; try restarting transaction。
死锁日志会在innodb status中记录。
show engine innodb status;
此语句会展示innodb监控信息,包含事务,文件IO,死锁,线程,内存和缓冲池等信息。
- INNODB MONITOR OUTPUT
- Per second averages calculated from the last 20 seconds
- BACKGROUND THREAD
- SEMAPHORES
- LATEST DETECTED DEADLOCK
- TRANSACTIONS
- FILE I/O
- INSERT BUFFER AND ADAPTIVE HASH INDEX
- LOG
- BUFFER POOL AND MEMORY
- ROW OPERATIONS
下面只展示死锁相关信息:
- LATEST DETECTED DEADLOCK
- ------------------------
- 2022-08-20 16:08:43 0x17e0
- *** (1) TRANSACTION:
- TRANSACTION 56390, ACTIVE 48 sec starting index read
- mysql tables in use 1, locked 1
- LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
- MySQL thread id 13, OS thread handle 3788, query id 1277 BOGON 192.168.0.101 root updating
- /* ApplicationName=DataGrip 2022.2 */ update a set age=19 where b_id=3
- *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
- RECORD LOCKS space id 227 page no 3 n bits 80 index PRIMARY of table `dps`.`a` trx id 56390 lock_mode X locks rec but not gap waiting
- Record lock, heap no 9 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
- 0: len 4; hex 80000002; asc ;;
- 1: len 6; hex 00000000dc45; asc E;;
- 2: len 7; hex 300000017018b8; asc 0 p ;;
- 3: len 5; hex 6873685f31; asc hsh_1;;
- 4: len 4; hex 80000018; asc ;;
- 5: len 4; hex 80000003; asc ;;
- *** (2) TRANSACTION:
- TRANSACTION 56389, ACTIVE 60 sec starting index read, thread declared inside InnoDB 5000
- mysql tables in use 1, locked 1
- 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
- MySQL thread id 12, OS thread handle 6112, query id 1321 BOGON 192.168.0.101 root updating
- /* ApplicationName=DataGrip 2022.2 */ update a set name='hsh_2' where b_id=3
- *** (2) HOLDS THE LOCK(S):
- RECORD LOCKS space id 227 page no 3 n bits 80 index PRIMARY of table `dps`.`a` trx id 56389 lock_mode X locks rec but not gap
- Record lock, heap no 9 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
- 0: len 4; hex 80000002; asc ;;
- 1: len 6; hex 00000000dc45; asc E;;
- 2: len 7; hex 300000017018b8; asc 0 p ;;
- 3: len 5; hex 6873685f31; asc hsh_1;;
- 4: len 4; hex 80000018; asc ;;
- 5: len 4; hex 80000003; asc ;;
- *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
- RECORD LOCKS space id 227 page no 4 n bits 72 index a_b_id_fk of table `dps`.`a` trx id 56389 lock_mode X waiting
- Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
- 0: len 4; hex 80000003; asc ;;
- 1: len 4; hex 80000002; asc ;;
- *** WE ROLL BACK TRANSACTION (1)
当事务2执行更新时,时通过外键更新的,所以不仅会请求 227:3:9 这把锁,同时也会在 227:4:6 这个外键索引上加锁。
当事务1再通过外键更新时,就请求 227:4:6 这把外键锁,此时事务2持有这把锁,由于事务1持有事务2请求的锁,
所以事务2无法释放持有的外键锁,死锁就会产生。这是MySQL检测到了死锁,就会kill掉事务2。
按如下语句执行事务:
步骤 | 事务1 id=56395 | 事务2 id=56396 |
1 | update a set name='hsh_2' where b_id = 3; | |
2 | update a set age=19 where b_id = 3; |
- [
- {
- "trx_id": "56395",
- "trx_state": "RUNNING",
- "trx_started": "2022-08-20 17:05:16",
- "trx_requested_lock_id": null,
- "trx_wait_started": null,
- "trx_weight": 4,
- "trx_mysql_thread_id": 12,
- "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": 3,
- "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,
- "lock_id": "56395:227:4:6",
- "lock_trx_id": "56395",
- "lock_mode": "X",
- "lock_type": "RECORD",
- "lock_table": "`dps`.`a`",
- "lock_index": "a_b_id_fk",
- "lock_space": 227,
- "lock_page": 4,
- "lock_rec": 6,
- "lock_data": "3, 2"
- },
- {
- "trx_id": "56396",
- "trx_state": "LOCK WAIT",
- "trx_started": "2022-08-20 17:05:33",
- "trx_requested_lock_id": "56396:227:4:6",
- "trx_wait_started": "2022-08-20 17:05:33",
- "trx_weight": 2,
- "trx_mysql_thread_id": 13,
- "trx_query": "/* ApplicationName=DataGrip 2022.2 */ update a\nset age=19\nwhere b_id = 3",
- "trx_operation_state": "starting index read",
- "trx_tables_in_use": 1,
- "trx_tables_locked": 1,
- "trx_lock_structs": 2,
- "trx_lock_memory_bytes": 1136,
- "trx_rows_locked": 1,
- "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,
- "lock_id": "56396:227:4:6",
- "lock_trx_id": "56396",
- "lock_mode": "X",
- "lock_type": "RECORD",
- "lock_table": "`dps`.`a`",
- "lock_index": "a_b_id_fk",
- "lock_space": 227,
- "lock_page": 4,
- "lock_rec": 6,
- "lock_data": "3, 2"
- }
- ]
从"lock_index": "a_b_id_fk" 可以看出此时的锁是外键锁,
锁的记录为 227:4:6 上的外键锁。
事务与锁 表中的具体字段说明,参见
information_schema.INNODB_TRX表详解_CaptHua的博客-CSDN博客_information_schema.innodb_trx