mysql版本:5.7

目的:在RC下,name列上仅有key索引,并发插入name时不出现重复数据

RC不加gap lock,并且复合select语句是不加锁的快照读,导致两个事务同时进行都可插入,测试如下:

client1:

mysql> set tx_isolation='read-committed';

mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set, 1 warning (0.00 sec) mysql> create table t (id int primary key, name int, key(name))engine=innodb;
Query OK, 0 rows affected (0.24 sec) ....... mysql> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
+----+------+
7 rows in set (0.00 sec) mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec) mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | OFF |
+---------------+-------+
1 row in set (0.03 sec) mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> insert into t select 8,8 from dual where not exists (select name from t where name=8);
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
+----+------+
8 rows in set (0.00 sec)

client2设置同client1,设置略,然后起事务插入:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> insert into t select 9,8 from dual where not exists (select name from t where name=8);
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 9 | 8 |
+----+------+
8 rows in set (0.00 sec)

可以看到并未阻塞,这不同于RR,在RR下会阻塞,因为加了gap lock。

难道这时候没有加任何锁吗,其实并不是,client1执行如下,并查看锁:

mysql> select name from t where name=8 lock in share mode;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 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 |
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
| 164163:469:4:10 | 164163 | S | RECORD | `test1`.`t` | name | 469 | 4 | 10 | 8, 9 |
| 164168:469:4:10 | 164168 | X | RECORD | `test1`.`t` | name | 469 | 4 | 10 | 8, 9 |
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)

看看加锁的数据。client2如下:

mysql> select name from t where name=8 lock in share mode;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 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 |
+----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
| 164168:469:4:9 | 164168 | S | RECORD | `test1`.`t` | name | 469 | 4 | 9 | 8, 8 |
| 164163:469:4:9 | 164163 | X | RECORD | `test1`.`t` | name | 469 | 4 | 9 | 8, 8 |
+----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)

看看加锁的数据,可见client1和2都上了锁,是在insert时上的。

那么为了能达到加锁阻塞的目的,可以使用如下方式,client1:

mysql> insert into t select 8,8 from dual where not exists (select name from t where name=8 for update);
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0

client2则阻塞:

mysql> insert into t select 9,8 from dual where not exists (select name from t where name=8 for update);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 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 |
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
| 164170:469:4:10 | 164170 | X | RECORD | `test1`.`t` | name | 469 | 4 | 10 | 8, 8 |
| 164169:469:4:10 | 164169 | X | RECORD | `test1`.`t` | name | 469 | 4 | 10 | 8, 8 |
+-----------------+-------------+-----------+-----------+-------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)

如果client1在client2阻塞时 commit:

mysql> insert into t select 8,8 from dual where not exists (select name from t where name=8 for update);
Query OK, 1 rows affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> commit;
Query OK, 0 rows affected (0.04 sec)

client2:

mysql> insert into t select 9,8 from dual where not exists (select name from t where name=8 for update);
Query OK, 0 rows affected (4.79 sec)
Records: 0 Duplicates: 0 Warnings: 0

还有一个需要注意的地方是,如果不加for update,则并发插入时,都会插入新数据,client1:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
+----+------+
8 rows in set (0.00 sec) mysql> insert into t select 9,9 from dual where not exists (select name from t where name=9);
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
| 9 | 9 |
+----+------+
9 rows in set (0.00 sec) mysql> commit;
Query OK, 0 rows affected (0.03 sec) mysql> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
| 9 | 9 |
| 10 | 9 |
+----+------+
10 rows in set (0.00 sec)

与client1并发执行的client2:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
+----+------+
8 rows in set (0.00 sec) mysql> insert into t select 10,9 from dual where not exists (select name from t where name=9);
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
| 10 | 9 |
+----+------+
9 rows in set (0.00 sec) mysql> commit;
Query OK, 0 rows affected (0.04 sec) mysql> select * from t;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
| 9 | 9 |
| 10 | 9 |
+----+------+
10 rows in set (0.00 sec)

可见,根本起不到不存在则插入的效果。

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

  1. mysql RR下不存在则插入

    主要看并发事务中不存在则插入(只有key索引)的阻塞情况. 表定义: mysql> desc user; +-------------+------------------+------+--- ...

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

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

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

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

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

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

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

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

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

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

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

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

  8. Mysql InnoDB下的两种行锁

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

  9. 项目总结01:JSP mysql SpringMvc下中国省市县三级联动下拉框

    JSP mysql SpringMvc下中国省市县三级联动下拉框 关键词 JSP  mysql数据库  SpringMvc  ajax   Controller层  Service层  中国地区  省 ...

随机推荐

  1. H3C交换机流量镜像

    今天需要对交换机进行本地流量镜像,在此记录: 交换机:H3C S5120 配置本地端口镜像时,用户首先要创建一个本地镜像组,然后为本地镜像组配置源端口和目的端口. 表1-1 配置本地端口镜像 操作 命 ...

  2. EBS _ALL, _TL, _VL, _V,_F,_VL,_A,_AVN and what else

    http://hi.baidu.com/einsteinalbert/item/54579250efc637abadc85705 _ALL, _TL, _VL, _V,_F,_VL,_A,_AVN a ...

  3. EBS 中查看LOV中的查询语句

    http://blog.csdn.net/shishun123/article/details/6874824 一直有实施顾问询问我XXForm的XX LOV是什么逻辑,取数SQL是什么来着,以前比较 ...

  4. 使用Xcode 7 beta免费真机调试iOS应用程序

    使用Xcode 7 beta免费真机调试iOS应用程序 六月 9, 2015  |   K-Res 发布   今天凌晨的WWDC15虽然没有熬夜守候吧,但也还是早起第一时间翻看了twitter的相关标 ...

  5. ECG心电图数据1

    最近在写一篇基于小波变换的ECG信号压缩算法的论文,遇到了怎样获取ECG信号测试数据的问题,在百度和专业论坛里搜索了一番,发现也有很多朋友为此发愁.现在论文写好了,投稿中,顺便也把怎样获取和处理ECG ...

  6. 【C#进阶】拥抱Lambda(一)

    写在开头,好奇从这里开始(当时让加查询条件,结果竟然是一句话来发挥神奇作用): this.TestGrade = CriteriaHelper.NewObject<ITestCase, DtoT ...

  7. 使用cropper插件进行图片裁剪 并上传

    cropper插件的使用和 github地址: github 官方实例 我参考的中文文档: https://www.cnblogs.com/baka-sky/p/8001577.html 因为我是.n ...

  8. 【转】SQL FOR XML简介及用法

    摘要:sql中的for xml语法为表转化为xml提供了很好的支持,当然使用同样的程序语言也能够达到同样的效果,但是有了for xml将使得这一切更加的方便. 主要内容: Select 的查询结果会作 ...

  9. 換根lca

    假設我們要求u,v,在根為rt情況下的lca 則lca為lca(u,v),lca(u,rt),lca(v,rt)中的深度的最大值

  10. elasticsearch中 refresh 和flush区别

    elasticsearch中有两个比较重要的操作:refresh 和 flush refresh操作 当我们向ES发送请求的时候,我们发现es貌似可以在我们发请求的同时进行搜索.而这个实时建索引并可以 ...