本文是读了<mysql是怎么运行的>作者加锁文章之后,想弄清楚insert的加的什么锁,搞的一个测试记录。
准备条件
1.操作的表(借用小孩子的表,侵权,我删)
CREATE TABLE hero (
number INT AUTO_INCREMENT,
name VARCHAR(100),
country varchar(100),
PRIMARY KEY (number),
UNIQUE KEY uk_name (name)
) Engine=InnoDB CHARSET=utf8;
INSERT INTO hero VALUES
(1, 'l刘备', '蜀'),
(3, 'z诸葛亮', '蜀'),
(8, 'c曹操', '魏'),
(15, 'x荀彧', '魏'),
(20, 's孙权', '吴');
最后形成的格式(借用作者小孩子的图)
2.mysql版本和隔离级别
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.32 |
+-----------+
1 row in set (0.00 sec)
mysql> select @@global.tx_isolation;
ERROR 1193 (HY000): Unknown system variable 'tx_isolation'
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
3.开启锁的日志信息和死锁信息
SHOW GLOBAL VARIABLES LIKE 'innodb_status_output_locks';
SET GLOBAL innodb_status_output_locks = ON;
show variables like "%innodb_print_all_deadlocks%";
set global innodb_print_all_deadlocks = 1;
4.开启多个会话,并用SHOW ENGINE INNODB STATUS \G查看加锁信息
加锁分析
1.记录不存在,插入带主键
开启两个事务
事务1,插入主键
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero VALUES(21, 'g关羽', '蜀');
Query OK, 1 row affected (0.00 sec)
SHOW ENGINE INNODB STATUS \G查看锁信息,什么都没有
事务2,也插入同样的主键
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero VALUES(21, 'g关羽', '蜀');
事务2会阻塞
SHOW ENGINE INNODB STATUS \G查看锁信息,只截取锁的部分,其余省略
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11042 lock mode S locks rec but not gap waiting
Record lock, heap no 8 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000015; asc ;;
1: len 6; hex 000000002b21; asc +!;;
2: len 7; hex 810000010e0110; asc ;;
3: len 7; hex 67e585b3e7bebd; asc g ;;
4: len 3; hex e89c80; asc ;;
------------------
TABLE LOCK table `world`.`hero` trx id 11042 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11042 lock mode S locks rec but not gap waiting
Record lock, heap no 8 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000015; asc ;;
1: len 6; hex 000000002b21; asc +!;;
2: len 7; hex 810000010e0110; asc ;;
3: len 7; hex 67e585b3e7bebd; asc g ;;
4: len 3; hex e89c80; asc ;;
---TRANSACTION 11041, ACTIVE 24 sec
2 lock struct(s), heap size 1128, 1 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 2028, query id 121 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11041 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11041 lock_mode X locks rec but not gap
Record lock, heap no 8 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000015; asc ;;
1: len 6; hex 000000002b21; asc +!;;
2: len 7; hex 810000010e0110; asc ;;
3: len 7; hex 67e585b3e7bebd; asc g ;;
4: len 3; hex e89c80; asc ;;
事务1给主键记录是number=21的加了x的记录锁,事务2要等待给当前记录加上s的记录锁,所以阻塞
index PRIMARY 代表的是number主键的名字是PRIMARY
hex 80000015 16进制代表number的值是21
hex 67e585b3e7bebd; utf8的值是g关羽
hex e89c80; utf8的值是蜀
如果什么都不做,事务2会自动等待超时
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
通过这个分析,看mysql的官网死锁的例子分析
然后看死锁日志
LATEST DETECTED DEADLOCK
------------------------
2023-11-22 16:03:29 0x1e14
*** (1) TRANSACTION:
TRANSACTION 11081, ACTIVE 10 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1128, 2 row lock(s)
MySQL thread id 16, OS thread handle 15580, query id 301 localhost ::1 root update
INSERT INTO world.hero VALUES(65, 'g????', '??')
*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11081 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11081 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (2) TRANSACTION:
TRANSACTION 11080, ACTIVE 20 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1128, 2 row lock(s)
MySQL thread id 15, OS thread handle 12456, query id 299 localhost ::1 root update
INSERT INTO world.hero VALUES(65, 'g????', '??')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11080 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11080 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
事务1的第一个操作为该行获取x的记录锁。事务2和事务3的操作都会导致重复键错误,并且它们都请求该行的s的记录锁。当事务1提交时,它释放该行上的x的记录锁,并授予事务2和事务3的排队共享锁请求。此时,会话2和3死锁:由于双方持有s的记录锁,这两个事务都不能获得该行的x的记录锁
2.记录不存在,插入不带主键
同上,事务1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero(name, country) VALUES( 'g关羽', '蜀');
Query OK, 1 row affected (0.00 sec)
SHOW ENGINE INNODB STATUS \G查看锁信息,什么都没有
事务2也同样的插入,会阻塞(图略,同上)
然后再SHOW ENGINE INNODB STATUS \G查看锁信息
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1128, 1 row lock(s), undo log entries 1
MySQL thread id 15, OS thread handle 12456, query id 113 localhost ::1 root update
INSERT INTO world.hero VALUES(21, 'g????', '??')
------- TRX HAS BEEN WAITING 5 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 77 page no 5 n bits 80 index uk_name of table `world`.`hero` trx id 11040 lock mode S waiting
Record lock, heap no 7 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 7; hex 67e585b3e7bebd; asc g ;;
1: len 4; hex 80000036; asc 6;;
------------------
TABLE LOCK table `world`.`hero` trx id 11040 lock mode IX
RECORD LOCKS space id 77 page no 5 n bits 80 index uk_name of table `world`.`hero` trx id 11040 lock mode S waiting
Record lock, heap no 7 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 7; hex 67e585b3e7bebd; asc g ;;
1: len 4; hex 80000036; asc 6;;
---TRANSACTION 11035, ACTIVE 14 sec
2 lock struct(s), heap size 1128, 1 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 2028, query id 111 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11035 lock mode IX
RECORD LOCKS space id 77 page no 5 n bits 80 index uk_name of table `world`.`hero` trx id 11035 lock_mode X locks rec but not gap
Record lock, heap no 7 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 7; hex 67e585b3e7bebd; asc g ;;
1: len 4; hex 80000036; asc 6;;
index uk_name 的country的唯一索引的名字是uk_name,事务1的唯一索引的uk_name的g关羽记录被加上了x的记录锁,事务2等待在此记录上加入s的next-key锁,所以一直阻塞,下面的唯一索引g关羽的记录
hex 67e585b3e7bebd; utf8的值是g关羽
hex 80000036; 唯一索引带的自增的主键id
3.记录存在,插入带主键
事务1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero VALUES(15, 'x荀彧', '吴') ;
ERROR 1062 (23000): Duplicate entry '15' for key 'hero.PRIMARY'
SHOW ENGINE INNODB STATUS \G查看锁信息
2 lock struct(s), heap size 1128, 1 row lock(s)
MySQL thread id 11, OS thread handle 2028, query id 131 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11043 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11043 lock mode S locks rec but not gap
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 8000000f; asc ;;
1: len 6; hex 000000002122; asc !";;
2: len 7; hex 820000011a0137; asc 7;;
3: len 7; hex 78e88d80e5bda7; asc x ;;
4: len 3; hex e9ad8f; asc ;;
给number=15的主键上了s的记录锁,所以不会阻塞
事务2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero VALUES(15, 'x荀彧', '吴') ;
ERROR 1062 (23000): Duplicate entry '15' for key 'hero.PRIMARY'
SHOW ENGINE INNODB STATUS \G查看锁信息
2 lock struct(s), heap size 1128, 1 row lock(s)
MySQL thread id 15, OS thread handle 12456, query id 133 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11044 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11044 lock mode S locks rec but not gap
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 8000000f; asc ;;
1: len 6; hex 000000002122; asc !";;
2: len 7; hex 820000011a0137; asc 7;;
3: len 7; hex 78e88d80e5bda7; asc x ;;
4: len 3; hex e9ad8f; asc ;;
---TRANSACTION 11043, ACTIVE 39 sec
2 lock struct(s), heap size 1128, 1 row lock(s)
MySQL thread id 11, OS thread handle 2028, query id 131 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11043 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11043 lock mode S locks rec but not gap
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 8000000f; asc ;;
1: len 6; hex 000000002122; asc !";;
2: len 7; hex 820000011a0137; asc 7;;
3: len 7; hex 78e88d80e5bda7; asc x ;;
4: len 3; hex e9ad8f; asc ;;
事务2也给number=15的主键记录上了s的记录锁,因为s的记录锁是兼容的,所以不会阻塞
******上面的语句换成insert ignore world.hero VALUES(15, 'x荀彧', '吴');是同样的效果,可以自己测试一下。
4.记录存在,插入不带主键
事务1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero(name, country) VALUES( 'x荀彧', '吴') ;
ERROR 1062 (23000): Duplicate entry 'x荀彧' for key 'hero.uk_name'
SHOW ENGINE INNODB STATUS \G查看锁信息
4 lock struct(s), heap size 1128, 2 row lock(s)
MySQL thread id 11, OS thread handle 2028, query id 141 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11045 lock mode IX
RECORD LOCKS space id 77 page no 5 n bits 80 index uk_name of table `world`.`hero` trx id 11045 lock mode S
Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 7; hex 78e88d80e5bda7; asc x ;;
1: len 4; hex 8000000f; asc ;;
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11045 lock_mode X locks rec but not gap
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11045 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
事务1给唯一索引记录(x荀彧)加上了s的next-key的锁,给主键记录supremum加上了x的锁和x的记录锁,所以不会阻塞,只会报唯一索引重复的错误
事务2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero(name, country) VALUES( 'x荀彧', '吴') ;
SHOW ENGINE INNODB STATUS \G查看锁信息
------------------
TABLE LOCK table `world`.`hero` trx id 11046 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11046 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
---TRANSACTION 11045, ACTIVE 27 sec
4 lock struct(s), heap size 1128, 2 row lock(s)
MySQL thread id 11, OS thread handle 2028, query id 141 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11045 lock mode IX
RECORD LOCKS space id 77 page no 5 n bits 80 index uk_name of table `world`.`hero` trx id 11045 lock mode S
Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 7; hex 78e88d80e5bda7; asc x ;;
1: len 4; hex 8000000f; asc ;;
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11045 lock_mode X locks rec but not gap
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11045 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
事务2要给主键supremum加x的next-key锁,所以一直阻塞等待,因为事务1已经上了一个x的next-key锁了
***********INSERT ignore INTO world.hero(name, country) VALUES( 'x荀彧', '吴') ;
INSERT INTO world.hero VALUES(30, 'x荀彧', '吴') ;
上面的两条语句也能达到同样的效果
如果换成INSERT INTO world.hero VALUES(16, 'x荀彧', '吴') ;,又会有怎样的效果的
效果和上面的一样,看事务1的加锁情况
4 lock struct(s), heap size 1128, 2 row lock(s)
MySQL thread id 11, OS thread handle 2028, query id 153 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11047 lock mode IX
RECORD LOCKS space id 77 page no 5 n bits 80 index uk_name of table `world`.`hero` trx id 11047 lock mode S
Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 7; hex 78e88d80e5bda7; asc x ;;
1: len 4; hex 8000000f; asc ;;
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11047 lock_mode X locks rec but not gap
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11047 lock_mode X locks gap before rec
Record lock, heap no 9 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 00000000273e; asc '>;;
2: len 7; hex 0200000089065f; asc _;;
3: len 7; hex 73e5ad99e69d83; asc s ;;
4: len 4; hex e9ad8f37; asc 7;;
上面主键supremum加的锁,换到了主键number=20的了,即number=16的下一个
事务2的锁也是替换了上面的了
------------------
TABLE LOCK table `world`.`hero` trx id 11048 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11048 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 9 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 00000000273e; asc '>;;
2: len 7; hex 0200000089065f; asc _;;
3: len 7; hex 73e5ad99e69d83; asc s ;;
4: len 4; hex e9ad8f37; asc 7;;
---TRANSACTION 11047, ACTIVE 19 sec
4 lock struct(s), heap size 1128, 2 row lock(s)
MySQL thread id 11, OS thread handle 2028, query id 153 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11047 lock mode IX
RECORD LOCKS space id 77 page no 5 n bits 80 index uk_name of table `world`.`hero` trx id 11047 lock mode S
Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 7; hex 78e88d80e5bda7; asc x ;;
1: len 4; hex 8000000f; asc ;;
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11047 lock_mode X locks rec but not gap
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11047 lock_mode X locks gap before rec
Record lock, heap no 9 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 00000000273e; asc '>;;
2: len 7; hex 0200000089065f; asc _;;
3: len 7; hex 73e5ad99e69d83; asc s ;;
4: len 4; hex e9ad8f37; asc 7;;
5.insert ignore into 和 insert into 加的锁大致一样
6.ON DUPLICATE KEY UPDATE,插入带主键
事务1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero VALUES(20, 's孙权', '吴') ON DUPLICATE KEY UPDATE country='魏';
Query OK, 2 rows affected (0.00 sec)
加锁分析
MySQL thread id 11, OS thread handle 2028, query id 163 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11049 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11049 lock_mode X locks rec but not gap
Record lock, heap no 9 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 000000002b29; asc +);;
2: len 7; hex 01000001310e3f; asc 1 ?;;
3: len 7; hex 73e5ad99e69d83; asc s ;;
4: len 3; hex e9ad8f; asc ;;
事务1,给主键number=20的加了一个x的记录锁,所以执行成功
事务2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero VALUES(20, 's孙权', '吴') ON DUPLICATE KEY UPDATE country='魏';
加锁分析
------------------
TABLE LOCK table `world`.`hero` trx id 11050 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11050 lock_mode X locks rec but not gap waiting
Record lock, heap no 9 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 000000002b29; asc +);;
2: len 7; hex 01000001310e3f; asc 1 ?;;
3: len 7; hex 73e5ad99e69d83; asc s ;;
4: len 3; hex e9ad8f; asc ;;
---TRANSACTION 11049, ACTIVE 18 sec
2 lock struct(s), heap size 1128, 1 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 2028, query id 163 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11049 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11049 lock_mode X locks rec but not gap
Record lock, heap no 9 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 000000002b29; asc +);;
2: len 7; hex 01000001310e3f; asc 1 ?;;
3: len 7; hex 73e5ad99e69d83; asc s ;;
4: len 3; hex e9ad8f; asc ;;
事务2也要给number=20的加了一个x的记录的锁,所以等待
7.ON DUPLICATE KEY UPDATE,插入不带主键
事务1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO world.hero(name, country) VALUES('s孙权', '吴') ON DUPLICATE KEY UPDATE country='魏5';
Query OK, 2 rows affected (0.00 sec)
4 lock struct(s), heap size 1128, 3 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 2028, query id 173 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11052 lock mode IX
RECORD LOCKS space id 77 page no 5 n bits 80 index uk_name of table `world`.`hero` trx id 11052 lock_mode X
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 7; hex 73e5ad99e69d83; asc s ;;
1: len 4; hex 80000014; asc ;;
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11052 lock_mode X locks rec but not gap
Record lock, heap no 10 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 000000002b2c; asc +,;;
2: len 7; hex 01000001320cc1; asc 2 ;;
3: len 7; hex 73e5ad99e69d83; asc s ;;
4: len 4; hex e9ad8f35; asc 5;;
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11052 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
事务1 给唯一索引(s孙权)加上了x的next-key的锁,给number=20的主键加上了x的记录锁,并给supremum加上了x的next-key的锁
同理事务也按上面的处理,加锁分析
------------------
TABLE LOCK table `world`.`hero` trx id 11053 lock mode IX
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11053 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
---TRANSACTION 11052, ACTIVE 18 sec
4 lock struct(s), heap size 1128, 3 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 2028, query id 173 localhost ::1 root
TABLE LOCK table `world`.`hero` trx id 11052 lock mode IX
RECORD LOCKS space id 77 page no 5 n bits 80 index uk_name of table `world`.`hero` trx id 11052 lock_mode X
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 7; hex 73e5ad99e69d83; asc s ;;
1: len 4; hex 80000014; asc ;;
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11052 lock_mode X locks rec but not gap
Record lock, heap no 10 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000014; asc ;;
1: len 6; hex 000000002b2c; asc +,;;
2: len 7; hex 01000001320cc1; asc 2 ;;
3: len 7; hex 73e5ad99e69d83; asc s ;;
4: len 4; hex e9ad8f35; asc 5;;
RECORD LOCKS space id 77 page no 4 n bits 80 index PRIMARY of table `world`.`hero` trx id 11052 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
事务2要给supremum加上x的next-key的锁的,所以一直等待
结论
对于同一语句来说,加不加主键,其实都是加了的,不加主键的主键默认是自增的id+1,在RR隔离级别下,
如果插入带主键,主键存在,insert和insert ignore会加s型的记录锁,ON DUPLICATE KEY UPDATE会加x的记录锁,主键不存在,insert和insert ignore会给前一个加入一个x的记录锁。
如果插入不带主键,insert和insert ignore正在插入的,会给下一个记录加一个x的next-key锁,ON DUPLICATE KEY UPDATE会当前记录一个x的记录锁和下一个记录的x的next-key的锁。
对于唯一的二级索引下,insert和insert ignore会加s的next-key的锁,ON DUPLICATE KEY UPDATE会加x的next-key的锁
对于RC级别,大家可以测试一下
最后,本人能力有限,如果上面的有纰漏和问题,欢迎大佬指出