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. 用C#开发的双色球走势图(原创)值得园友拥有

    首先声明,个人纯粹无聊之作,不作商业用途. 我相信每个人都拥有一个梦想那就是有朝一日能中500W,这个也一直是我的梦想,并默默每一期双色球或多或少要贡献自己一点点力量,本人并不属于那种铁杆的彩票迷,每 ...

  2. AbpZero之企业微信---登录(拓展第三方auth授权登录)---第二步:开始逐步实现企业微信登录

    上回分解到AbpZero的auth登录机制,这里我们开始着手逐步实现我们的auth登录. 我们新建一个类库XXXX.Web.Authentication.External 在类库下新建一个类QYWec ...

  3. MVVM前端框架

    早开始接触MVVM框架的时候,是在学习WPF的时候,后面陆陆续续接触到了很多的前端JS框架,个人觉得大同小异,也没有去研究源代码,所以都停留在使用的阶段.当然对于我来说,使用这些JS框架,最关注的无非 ...

  4. ADO.NET系列之Connection对象

    ADO.NET系列之Connection对象 ADO.NET系列之Command对象 ADO.NET系列之DataAdapter对象 ADO.NET系列之事务和调用存储过程 ADO.NET概念 ADO ...

  5. .net core grpc consul 实现服务注册 服务发现 负载均衡(二)

    在上一篇 .net core grpc 实现通信(一) 中,我们实现的grpc通信在.net core中的可行性,但要在微服务中真正使用,还缺少 服务注册,服务发现及负载均衡等,本篇我们将在 .net ...

  6. MPU6050学习笔记(电源管理器1、2)

    Technorati Tags: 嵌入式开发.模块开发 寄存器107号:电源管理器1 PWR_MGMT_1: Description: This register allows the user to ...

  7. SqlAlchemy操作(一)

    博客转载于 http://www.cnblogs.com/haiyan123/p/8270520.html 一. 介绍 SQLAlchemy是一个基于Python实现的ORM框架.该框架建立在 DB ...

  8. day111 爬虫第一天

    一.模拟浏览器发请求. import requests r1 =requests.get( url ="https://dig.chouti.com/", headers ={ & ...

  9. 782. Transform to Chessboard

    An N x N board contains only 0s and 1s. In each move, you can swap any 2 rows with each other, or an ...

  10. iOS method swizz

    1: 防止按钮在一定时间内重复响应默认1秒 // // UIButton+AvoidDoubleClick.h // 51WaywardShop // // Created by jisa on 20 ...