mysql rr 更新失败_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.00sec)

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.00sec)

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.00sec)

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.00sec)

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.00sec)

mysql> select * from user where name='d';

Emptyset (0.02sec)

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.02sec)

Records:1 Duplicates: 0 Warnings: 0

并不会阻塞。

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

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

mysql> select * frominformation_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 * frominformation_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.00sec)

Records:0 Duplicates: 0 Warnings: 0mysql> 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.00sec)

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.00sec)

Records:0 Duplicates: 0 Warnings: 0mysql> 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'的记录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值