• mysql RR下不存在则插入


    主要看并发事务中不存在则插入(只有key索引)的阻塞情况。

    表定义:

    mysql> desc user;
    +-------------+------------------+------+-----+-------------------+----------------+
    | Field       | Type             | Null | Key | Default           | Extra          |
    +-------------+------------------+------+-----+-------------------+----------------+
    | id          | int(10) unsigned | NO   | PRI | NULL              | auto_increment |
    | name        | varchar(50)      | NO   | MUL | NULL              |                |
    | password    | char(20)         | NO   |     | NULL              |                |
    | regist_time | timestamp        | NO   |     | CURRENT_TIMESTAMP |                |
    +-------------+------------------+------+-----+-------------------+----------------+
    4 rows in set (0.00 sec)

    事务隔离级别:RR

    mysql版本:5.7

    client1:

    mysql> begin;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select * from user;
    +----+------+----------+---------------------+
    | id | name | password | regist_time         |
    +----+------+----------+---------------------+
    |  1 | a    | a        | 2018-03-11 16:32:43 |
    |  2 | b    | b        | 2018-03-11 16:33:09 |
    |  3 | c    | c        | 2018-03-11 16:33:39 |
    +----+------+----------+---------------------+
    3 rows in set (0.00 sec)
    
    mysql> insert into user(name,password) select 'd','d' from dual where not exist (select name from user where name='d');
    Query OK, 1 row affected (0.00 sec)
    Records: 1  Duplicates: 0  Warnings: 0 mysql
    > select * from user; +----+------+----------+---------------------+ | id | name | password | regist_time | +----+------+----------+---------------------+ | 1 | a | a | 2018-03-11 16:32:43 | | 2 | b | b | 2018-03-11 16:33:09 | | 3 | c | c | 2018-03-11 16:33:39 | | 4 | d | d | 2018-03-11 17:03:35 | +----+------+----------+---------------------+ 4 rows in set (0.00 sec)

    然后启动client2:

    mysql> begin;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select * from user;
    +----+------+----------+---------------------+
    | id | name | password | regist_time         |
    +----+------+----------+---------------------+
    |  1 | a    | a        | 2018-03-11 16:32:43 |
    |  2 | b    | b        | 2018-03-11 16:33:09 |
    |  3 | c    | c        | 2018-03-11 16:33:39 |
    +----+------+----------+---------------------+
    3 rows in set (0.00 sec)
    
    mysql> select * from user where name='d';
    Empty set (0.02 sec)
    
    mysql> insert into user (name,password) select 'd','d' from dual where not exists (select name from user where name='d');

    client2 执行“ insert into user (name,password) select 'd','d' from dual where not exists (select name from user where name='d'); ”出现阻塞,直到超时或client1 commit。

    client2 直接执行插入操作则不会阻塞:

    mysql> insert into user(name, password) values ('d','d');
    Query OK, 1 row affected (0.00 sec)

    client2 执行:

    mysql> insert into user (name,password) select 'e','e' from dual where not exists (select name from user where name='e');

    也会出现阻塞。但是执行:

    mysql> insert into user (name,password) select '12','12' from dual where not exists (select name from user where name='12');
    Query OK, 1 row affected (0.02 sec)
    Records: 1  Duplicates: 0  Warnings: 0

    并不会阻塞。

    另:如果已经存在name='d'的数据,client1执行"insert not exists"后并不会插入也不会加锁,client2执行时也不会阻塞。

    查看锁(client2 插入'd'时的情况):

    mysql> 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 |
    +-------------------------+-----------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
    | 422016582501824:462:4:8 | 422016582501824 | S         | RECORD    | `test1`.`user` | name       |        462 |         4 |        8 | 'd', 11   |
    | 162094:462:4:8          | 162094          | X         | RECORD    | `test1`.`user` | name       |        462 |         4 |        8 | 'd', 11   |
    +-------------------------+-----------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
    2 rows in set, 1 warning (0.02 sec)

    client2 当插入'z'时也会阻塞,但lock_data还会是:

    mysql> 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              |
    +----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+------------------------+
    | 162131:462:4:1 | 162131      | X         | RECORD    | `test1`.`user` | name       |        462 |         4 |        1 | supremum pseudo-record |
    | 162094:462:4:1 | 162094      | S         | RECORD    | `test1`.`user` | name       |        462 |         4 |        1 | supremum pseudo-record |
    +----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+------------------------+
    2 rows in set, 1 warning (0.00 sec)

    也就是'z'是加锁的上界,插入'x'和'~'也是这种情况。

    之所以'12'不会锁,'d'和其以后的都会锁,是因为mysql为了防止幻读,还锁住了下一行,因为最大的是'd',所以锁住区域为('d', +∞),另一个区域是('c', 'd')。如果插入的不是这个区域的都不会阻塞。

    RC和RR加锁区别请见:RR和RC复合语句加锁

    当client2 插入'A'、'B'时居然不阻塞也插入不了:

    mysql> insert into user (name,password) select 'A','A' from dual where not exists (select name from user where name='A');
    Query OK, 0 rows affected (0.00 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> insert into user (name,password) select 'B','B' from dual where not exists (select name from user where name='B');
    Query OK, 0 rows affected (0.00 sec)
    Records: 0  Duplicates: 0  Warnings: 0

    client1也插入不了'A',只有直接执行时才可以:

    mysql> insert into user (name,password) select 'A','A' from dual where not exists (select name from user where name='A');
    Query OK, 0 rows affected (0.00 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> insert into user(name,password) values('A','A');
    Query OK, 1 row affected (0.00 sec)

    之所以出现无法插入'A'、'B',是因为不区分大小写,测试一下便知:

    mysql> select * from user where name='a';
    +----+------+----------+---------------------+
    | id | name | password | regist_time         |
    +----+------+----------+---------------------+
    |  1 | a    | a        | 2018-03-11 16:32:43 |
    | 44 | A    | A        | 2018-03-11 20:56:42 |
    +----+------+----------+---------------------+
    2 rows in set (0.00 sec)

    要想区分大小写,建表时需要相应设置,也可以在查询时使用:

    mysql> select * from user where binary name='a';
    +----+------+----------+---------------------+
    | id | name | password | regist_time         |
    +----+------+----------+---------------------+
    |  1 | a    | a        | 2018-03-11 16:32:43 |
    +----+------+----------+---------------------+
    1 row in set (0.01 sec)

    另:on duplicate key只适用于unique key,如果不是unique,总是会插入

    mysql> insert into user(name,password) values('d','d') on duplicate key update password='e';

    这时会插入一条name='d',password='d'的记录。

  • 相关阅读:
    python -- 面向对象
    python应用----函数
    python
    python 基础应用5-简单购物车
    python 基础知识5-集合
    python 基础应用4
    python 基础知识4
    python 基础知识3-列表元祖
    python 基础应用3
    无法进入局域网远程桌面--Windows防火墙设置
  • 原文地址:https://www.cnblogs.com/drizzlewithwind/p/8545138.html
Copyright © 2020-2023  润新知