主要看并发事务中不存在则插入(只有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'的记录。

mysql RR下不存在则插入的更多相关文章

  1. mysql RC下不存在则插入

    mysql版本:5.7 目的:在RC下,name列上仅有key索引,并发插入name时不出现重复数据 RC不加gap lock,并且复合select语句是不加锁的快照读,导致两个事务同时进行都可插入, ...

  2. 我的MYSQL学习心得(八) 插入 更新 删除

    我的MYSQL学习心得(八) 插入 更新 删除 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得( ...

  3. Mysql数据库实践操作之————批量插入数据(100万级别的数据)

    第一种方法:使用insert into 插入 从Redis每次获取100条数据,根据条件去插入到Mysql数据库中: 条件: 如果当前队列中的值大于1000条,则会自动的条用该方法,该方法每次获取从队 ...

  4. MySQL RR隔离 读一致性

    MySQL RR 模式下 事务隔离问题: Session 1: mysql> select * from test; +------+------+ | id | name | +------+ ...

  5. mysql三种带事务批量插入

    原文:mysql三种带事务批量插入 c#之mysql三种带事务批量插入 前言 对于像我这样的业务程序员开发一些表单内容是家常便饭的事情,说道表单 我们都避免不了多行内容的提交,多行内容保存,自然要用到 ...

  6. python+mysql:实现一千万条数据插入数据库

    作业要求 构建一个关系模式和课本中的关系movies(title,year,length,movietype,studioname,producerC)一样的关系,名称自定,在这个关系中插入1000万 ...

  7. 如何在mysql客户端即mysql提示符下执行操作系统命令

    环境描述: mysql版本:5.5.57-log 操作系统版本:Red Hat Enterprise Linux Server release 6.6 (Santiago) 需求描述: 在mysql的 ...

  8. 关于mysql安装后在客户端cmd插入语句无法执行的问题

    关于mysql安装后在客户端cmd插入语句无法执行的问题 因为windows cmd默认字符集是gbk,当character_set_client=utf8时,cmd中出现中文会报错:characte ...

  9. Mysql InnoDB下的两种行锁

    今天例举2种常见的Mysql InnoDB下的行锁 现有表dr_test(id pk, name) 数据是 1 zhangsan2 lisi3 wangwu 例子1 事务1 update dr_tes ...

随机推荐

  1. hdu 4950 打怪

    http://acm.hdu.edu.cn/showproblem.php?pid=4950 给定怪兽血量h,你攻击力a,怪物回血力b,你攻击k次要休息一次,问能否杀死怪兽 特判一次打死怪兽的情况和第 ...

  2. 从SEQUENCE跳号说起

    http://blog.csdn.net/agaric717/article/details/6690890 一个应用上线后发现一个使用SEQUENCE值来生成的主键经常出现断号,而且断号不是一两个, ...

  3. python的数据存储

    Python存储数据 使用json.dump()和json.load() 不管专注的是什么,程序都把用户提供的信息存储在列表和字典等数据结构中.用户关闭程序时,你几乎总是要保存他们提供的信息:一种简单 ...

  4. ArcGIS下图层范围不正确的两种处理方式

    ArcGIS下图层范围不正确,偶尔能碰上这种情况,主要表现为“缩放至图层”时,其显示范围与该图层内所有要素的外包围盒范围不一致.针对这个问题,有两种解决办法. 方法一:导出数据.新创建含有要素的Sha ...

  5. Alwayson--配置只读请求

    场景:有三台服务器SQLNode131,SQLNode132 ,SQLNode133: 1) 三台服务器加入域DCDemo.com 2) 三台服务器使用端口访问数据库 3) 三台服务器构建故障转移群集 ...

  6. [翻译]NUnit---Sequential and SetCulture and SetUICulture Attributes(十八)

    Sequential特性用于在测试用例上指定NUnit通过为测试提供的参数选择单一值生产测试用例,并且不会生产额外的组合. Note:如果参数数据由多个特性提供,那么NUnit使用数据项的顺序是随机的 ...

  7. Python 数据结构与算法——桶排序

    #简单的桶排序 def bucksort(A): bucks = dict() # 定义一个桶变量,类型为字典 for i in A: bucks.setdefault(i,[]) # 每个桶默认为空 ...

  8. Microsoft.Web.Administration操作IIS7时的权限设置

    在用Microsoft.Web.Administration操作IIS7时,你可能会遇到如下权限错误: 文件名: redirection.config错误: 由于权限不足而无法读取配置文件 如下图: ...

  9. docker 多阶段构建

    构建镜像最具挑战性的一点是使镜像大小尽可能的小.Dockerfile中的每条指令都为图像添加了一个图层,您需要记住在移动到下一层之前清理任何不需要的工件.对于多阶段构建,您可以在Dockerfile中 ...

  10. .Net Core2.0中使用ADO.NET

    学习了解.NET CORE有段时间,没有用其做项目的主要原因就是这么多年积累的类库兼容问题.今天就先解决SqlHelper的兼容性: 建立类库,目标框架选择.NET Core2.0,复制粘贴代码. 问 ...