zoukankan      html  css  js  c++  java
  • MySQL--REPLACE INTO加锁测试01

    测试需求

    在MySQL官方文档中有如下描述:

    https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html
    
    REPLACE is done like an INSERT if there is no collision on a unique key. Otherwise, an exclusive next-key lock is placed on the row to be replaced.
    
    

    在已提交读事务隔离级别下,官方文档有如下描述:

    For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE), UPDATE statements, and DELETE statements, InnoDB locks only index records, not the gaps before them, and thus permits the free insertion of new records next to locked records. 
    Gap locking is only used for foreign-key constraint checking and duplicate-key checking.
    
    https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html
    

    测试场景

    • MySQL版本: 5.7.29
    • 事务级别: READ-COMMITTED

    测试数据

    
    DROP TABLE IF EXISTS tb1001;
    CREATE TABLE `tb1001` (
      `id` INT(11) NOT NULL AUTO_INCREMENT,
      `c1` INT(11) NOT NULL,
      `c2` INT(11) NOT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `UNI_C1` (`c1`)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8;
    INSERT INTO TB1001(C1,C2)SELECT 1,1;
    INSERT INTO TB1001(C1,C2)SELECT 3,3;
    INSERT INTO TB1001(C1,C2)SELECT 5,5;
    INSERT INTO TB1001(C1,C2)SELECT 7,7;
    

    测试操作

    会话1先执行:

    BEGIN;
    REPLACE INTO tb1001(c1,c2)VALUES(3,33);
    

    测试01

    会话2执行(被阻塞):

    SELECT C1 FROM TB1001 WHERE C1=3 FOR UPDATE;
    

    查看阻塞信息:

    SELECT * FROM information_schema.innodb_locks;
    +----------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
    | lock_id        | lock_trx_id | lock_mode | lock_type | lock_table      | lock_index | lock_space | lock_page | lock_rec | lock_data |
    +----------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
    | 15464:1896:4:3 | 15464       | X         | RECORD    | `test`.`tb1001` | UNI_C1     |       1896 |         4 |        3 | 3         |
    | 15459:1896:4:3 | 15459       | X         | RECORD    | `test`.`tb1001` | UNI_C1     |       1896 |         4 |        3 | 3         |
    +----------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
    2 rows in set, 1 warning (0.00 sec)
    
    
    SHOW ENGINE INNODB STATUS G
    
    ------------
    TRANSACTIONS
    ------------
    Trx id counter 15465
    Purge done for trx's n:o < 15464 undo n:o < 0 state: running but idle
    History list length 33
    LIST OF TRANSACTIONS FOR EACH SESSION:
    ---TRANSACTION 421744043505488, not started
    0 lock struct(s), heap size 1136, 0 row lock(s)
    ---TRANSACTION 15464, ACTIVE 85 sec starting index read
    mysql tables in use 1, locked 1
    LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
    MySQL thread id 59, OS thread handle 140265625663232, query id 517 127.0.0.1 mysql_admin statistics
    SELECT C1 FROM TB1001 WHERE C1=3 FOR UPDATE
    ------- TRX HAS BEEN WAITING 35 SEC FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 1896 page no 4 n bits 72 index UNI_C1 of table `test`.`tb1001` trx id 15464 lock_mode X locks rec but not gap waiting
    Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
     0: len 4; hex 80000003; asc     ;;
     1: len 4; hex 80000002; asc     ;;
    
    ------------------
    ---TRANSACTION 15459, ACTIVE 45 sec
    4 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2
    MySQL thread id 58, OS thread handle 140265625122560, query id 519 127.0.0.1 mysql_admin starting
    SHOW ENGINE INNODB STATUS
    --------
    
    

    测试02

    会话2执行(被阻塞):

    SELECT C1 FROM TB1001 WHERE C1=5;
    

    查看锁信息:

    SELECT * FROM information_schema.innodb_locks;
    
    +----------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
    | lock_id        | lock_trx_id | lock_mode | lock_type | lock_table      | lock_index | lock_space | lock_page | lock_rec | lock_data |
    +----------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
    | 15464:1896:4:4 | 15464       | X         | RECORD    | `test`.`tb1001` | UNI_C1     |       1896 |         4 |        4 | 5         |
    | 15459:1896:4:4 | 15459       | X         | RECORD    | `test`.`tb1001` | UNI_C1     |       1896 |         4 |        4 | 5         |
    +----------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
    2 rows in set, 1 warning (0.00 sec)
    
    
    
    SHOW ENGINE INNODB STATUS G
    
    ------------
    TRANSACTIONS
    ------------
    Trx id counter 15465
    Purge done for trx's n:o < 15464 undo n:o < 0 state: running but idle
    History list length 33
    LIST OF TRANSACTIONS FOR EACH SESSION:
    ---TRANSACTION 421744043505488, not started
    0 lock struct(s), heap size 1136, 0 row lock(s)
    ---TRANSACTION 15464, ACTIVE 179 sec starting index read
    mysql tables in use 1, locked 1
    LOCK WAIT 2 lock struct(s), heap size 1136, 2 row lock(s)
    MySQL thread id 59, OS thread handle 140265625663232, query id 523 127.0.0.1 mysql_admin statistics
    SELECT C1 FROM TB1001 WHERE C1=5 FOR UPDATE
    ------- TRX HAS BEEN WAITING 13 SEC FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 1896 page no 4 n bits 72 index UNI_C1 of table `test`.`tb1001` trx id 15464 lock_mode X locks rec but not gap waiting
    Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
     0: len 4; hex 80000005; asc     ;;
     1: len 4; hex 80000003; asc     ;;
    
    ------------------
    ---TRANSACTION 15459, ACTIVE 139 sec
    4 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2
    MySQL thread id 58, OS thread handle 140265625122560, query id 524 127.0.0.1 mysql_admin starting
    SHOW ENGINE INNODB STATUS
    --------
    
    

    测试03

    会话2执行(被阻塞):

    INSERT INTO TB1001(C1,C2)SELECT 4,4;
    

    查看锁信息:

    SELECT * FROM information_schema.innodb_locks;
    
    +----------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
    | lock_id        | lock_trx_id | lock_mode | lock_type | lock_table      | lock_index | lock_space | lock_page | lock_rec | lock_data |
    +----------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
    | 15464:1896:4:4 | 15464       | X,GAP     | RECORD    | `test`.`tb1001` | UNI_C1     |       1896 |         4 |        4 | 5         |
    | 15459:1896:4:4 | 15459       | X         | RECORD    | `test`.`tb1001` | UNI_C1     |       1896 |         4 |        4 | 5         |
    +----------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
    2 rows in set, 1 warning (0.00 sec)
    
    
    
    SHOW ENGINE INNODB STATUS G
    
    ------------
    TRANSACTIONS
    ------------
    Trx id counter 15465
    Purge done for trx's n:o < 15464 undo n:o < 0 state: running but idle
    History list length 33
    LIST OF TRANSACTIONS FOR EACH SESSION:
    ---TRANSACTION 421744043505488, not started
    0 lock struct(s), heap size 1136, 0 row lock(s)
    ---TRANSACTION 15464, ACTIVE 484 sec inserting
    mysql tables in use 1, locked 1
    LOCK WAIT 2 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 1
    MySQL thread id 59, OS thread handle 140265625663232, query id 529 127.0.0.1 mysql_admin executing
    INSERT INTO TB1001(C1,C2)SELECT 4,4
    ------- TRX HAS BEEN WAITING 48 SEC FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 1896 page no 4 n bits 72 index UNI_C1 of table `test`.`tb1001` trx id 15464 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 80000005; asc     ;;
     1: len 4; hex 80000003; asc     ;;
    
    ------------------
    ---TRANSACTION 15459, ACTIVE 444 sec
    4 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2
    MySQL thread id 58, OS thread handle 140265625122560, query id 531 127.0.0.1 mysql_admin starting
    SHOW ENGINE INNODB STATUS
    --------
    
    

    测试04

    会话2执行(执行成功):

    INSERT INTO TB1001(C1,C2)SELECT 6,7;
    

    测试结论

    当REPLACE INTO插入数据(c1=3,c2=33)和现有数据(c1=3,c2=3)在唯一索引idx_c1上冲突时,由于目前idx_c1上数据为(1,3,5,7),因此会:

    • 对c1=3的索引记录加行锁
    • 对c1=3的索引记录的下一条记录(c1=5)加行锁
    • 对c1=3的索引记录到c1=5索引记录之间加间隙锁
  • 相关阅读:
    js冒泡排序
    总结常见疑问
    第八课 课程重点(js语句:条件、循环)
    第九课 课程重点(js语句:获取时间、数字取值、定时器)
    利用NABCD模型进行竞争性需求分析
    运行结果及总结~张萍萍
    测试与调试 滕娟
    面向对象分析设计
    设计类图 201303014029 于海飞
    SRS文档 王倩倩 201303014004
  • 原文地址:https://www.cnblogs.com/gaogao67/p/14635013.html
Copyright © 2011-2022 走看看