RC,RR隔离级别下对select .. for update
的表现
准备环境
mysql版本: 8.0.19 MySQL Community Server - GPL
CREATE TABLE `t` (
`id` int NOT NULL,
`c` int DEFAULT NULL,
`d` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
insert into t values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);
mysql> select * from t;
+----+------+------+
| id | c | d |
+----+------+------+
| 0 | 0 | 0 |
| 5 | 5 | 5 |
| 10 | 10 | 10 |
| 15 | 15 | 15 |
| 20 | 20 | 20 |
| 25 | 25 | 25 |
+----+------+------+
6 rows in set (0.00 sec)
RC隔离级别锁住非索引列
分别开启两个session.
session1 | session2 |
---|---|
transaction_isolation =READ-COMMITTED | transaction_isolation =READ-COMMITTED |
begin; | |
select * from t where d=5 for update; (5,5,5) | |
update t set d=5 where id=0; | |
select * from t where d=5 for update; (0,0,5)(5,5,5) | |
update t set d=5 where id=0;(夯住) update t set d=5 where id=5;(夯住) | |
commit; |
锁的范围是d=5的行
RR隔离级别锁住非索引列
分别开启两个session:
session1 | session2 |
---|---|
begin; | |
select * from t where d=5 for update; | |
update t set d=2 where id=5(锁住); update t set d=2 where id=0;(锁住) /U1/update t set d=2 where id=10;(锁住){琐的类型参考下文} | |
insert into t values (1,1,1)锁住(INSERT_INTENTION 插入意向缩); | |
commit; |
U1:
session1: select * from t where d=5 for update;
session2: update t set d=2 where id=10;
mysql> select * from innodb_lock_waits\G
*************************** 1. row ***************************
wait_started: 2023-02-16 03:45:04
wait_age: 00:00:02
wait_age_secs: 2
locked_table: `sbtest`.`t`
locked_table_schema: sbtest
locked_table_name: t
locked_table_partition: NULL
locked_table_subpartition: NULL
locked_index: PRIMARY
locked_type: RECORD
waiting_trx_id: 945508
waiting_trx_started: 2023-02-16 03:45:04
waiting_trx_age: 00:00:02
waiting_trx_rows_locked: 1
waiting_trx_rows_modified: 0
waiting_pid: 41
waiting_query: update t set d=2 where id=10
waiting_lock_id: 140037579886032:188:4:4:140037475860968
waiting_lock_mode: X,REC_NOT_GAP(行级别排它锁)
blocking_trx_id: 945501
blocking_pid: 40
blocking_query: NULL
blocking_lock_id: 140037579885160:188:4:4:140037475855096
blocking_lock_mode: X(排它锁)
blocking_trx_started: 2023-02-16 03:40:31
blocking_trx_age: 00:04:35
blocking_trx_rows_locked: 7
blocking_trx_rows_modified: 0
sql_kill_blocking_query: KILL QUERY 40
sql_kill_blocking_connection: KILL 40
1 row in set (0.00 sec)
锁的范围是(0,5],(5,10)
RC隔离界别锁住普通索引列
分别开启两个session:
session1 | session2 |
---|---|
transaction_isolation =READ-COMMITTED | transaction_isolation =READ-COMMITTED |
begin; | |
select * from t where c=5 for update; | |
update t set c=5 where id=5;(锁住) update t set c=5 where id=0;(正常执行) insert into t values (6,6,6);(正常执行 | |
select * from t; 多加一行(6,6,6) | |
commit; | |
锁的范围是c=5的行 |
RR隔离级别锁住普通索引列
分别开启两个session:
session1 | session2 |
---|---|
begin; | |
select * from t where c=5 for update; | |
update t set c=2 where id=10;(锁住)X,GAP,INSERT_INTENTION | |
insert into t values (1,1,1);(锁住)X,GAP,INSERT_INTENTION | |
commit; |
锁的范围:(0,5],(5,10)
RC隔离级别锁住主键索引列
分别开启两个session
session1 | session2 |
---|---|
transaction_isolation =READ-COMMITTED | transaction_isolation =READ-COMMITTED |
begin; | |
select * from t where id=0 for update; | |
update t set c=5 where id=0;(锁住)(X,REC_NOT_GAP) | |
insert into t values (1,1,1); | |
select * from t; | |
(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25),(1,1,1); | |
commit; | |
锁的范围是id=0的行 |
RR隔离级别锁住主键索引列
分别开启两个session
session1 | session2 |
---|---|
begin; | |
select * from t where id=5 for update; | |
update t set c=1 where id=5;(锁住)X,REC_NOT_GAP | |
update t set c=1 where id=0;(正常执行) | |
select * from t where id=0; (0,1,0) | |
commit; | |
锁的范围是id=5的行 |