mysql在存在主键冲突或者唯一键冲突的情况下,根据插入策略不同,一般有以下三种避免方法。

1、insert ignore

2、replace into

3、insert on duplicate key update

注意,除非表有一个PRIMARY KEY或UNIQUE索引,否则,使用以上三个语句没有意义,与使用单纯的INSERT INTO相同。

一、insert ignore

insert ignore会忽略数据库中已经存在的数据(根据主键或者唯一索引判断),如果数据库没有数据,就插入新的数据,如果有数据的话就跳过这条数据.

Case:

表结构如下:

复制代码

root:test> show create table t3\G

*************************** 1. row ***************************

Table: t3

Create Table: CREATE TABLE t3 (

id int(11) NOT NULL AUTO_INCREMENT,

c1 int(11) DEFAULT NULL,

c2 varchar(20) DEFAULT NULL,

c3 int(11) DEFAULT NULL,

PRIMARY KEY (id),

UNIQUE KEY uidx_c1 (c1)

) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8

1 row in set (0.00 sec)

root:test> select * from t3;

±—±-----±-----±-----+

| id | c1 | c2 | c3 |

±—±-----±-----±-----+

| 1 | 1 | a | 1 |

| 2 | 2 | a | 1 |

| 8 | NULL | NULL | 1 |

| 14 | 4 | bb | NULL |

| 17 | 5 | cc | 4 |

±—±-----±-----±-----+

5 rows in set (0.00 sec)

复制代码

测试插入唯一键冲突的数据

root:test> insert ignore into t3 (c1,c2,c3) values(5,‘cc’,4),(6,‘dd’,5); Query OK, 1 row affected, 1 warning (0.01 sec)

Records: 2 Duplicates: 1 Warnings: 1

如下,可以看到只插入了(6,‘dd’,5)这条,同时有一条warning提示有重复的值。

复制代码

root:test> show warnings;

±--------±-----±--------------------------------------+

| Level | Code | Message |

±--------±-----±--------------------------------------+

| Warning | 1062 | Duplicate entry ‘5’ for key ‘uidx_c1’ |

±--------±-----±--------------------------------------+

1 row in set (0.00 sec)

root:test> select * from t3;

±—±-----±-----±-----+

| id | c1 | c2 | c3 |

±—±-----±-----±-----+

| 1 | 1 | a | 1 |

| 2 | 2 | a | 1 |

| 8 | NULL | NULL | 1 |

| 14 | 4 | bb | NULL |

| 17 | 5 | cc | 4 |

| 18 | 6 | dd | 5 |

±—±-----±-----±-----+

6 rows in set (0.00 sec)

复制代码

重新查询表结构,发现虽然只增加了一条记录,但是AUTO_INCREMENT还是增加了2个(18变成20)

复制代码

root:test> show create table t3\G

*************************** 1. row ***************************

Table: t3

Create Table: CREATE TABLE `t3` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`c1` int(11) DEFAULT NULL,

`c2` varchar(20) DEFAULT NULL,

`c3` int(11) DEFAULT NULL,

PRIMARY KEY (`id`),

UNIQUE KEY `uidx_c1` (`c1`)

) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8

1 row in set (0.00 sec)

复制代码

二、replace into

replace into 首先尝试插入数据到表中。 如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据,否则,直接插入新数据。

使用replace into,你必须具有delete和insert权限

Case:

复制代码

root:test> show create table t3\G

*************************** 1. row ***************************

Table: t3

Create Table: CREATE TABLE t3 (

id int(11) NOT NULL AUTO_INCREMENT,

c1 int(11) DEFAULT NULL,

c2 varchar(20) DEFAULT NULL,

c3 int(11) DEFAULT NULL,

PRIMARY KEY (id),

UNIQUE KEY uidx_c1 (c1)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

1 row in set (0.00 sec)

root:test> select * from t3;

±—±-----±-------±-----+

| id | c1 | c2 | c3 |

±—±-----±-------±-----+

| 1 | 1 | cc | 4 |

| 2 | 2 | dd | 5 |

| 3 | 3 | qwewqe | 3 |

±—±-----±-------±-----+

3 rows in set (0.00 sec)

复制代码

插入一条与记录id=3存在唯一键(列c1)冲突的数据

复制代码

root:test> replace into t3 (c1,c2,c3) values(3,‘new’,8);

Query OK, 2 rows affected (0.02 sec)

root:test> select * from t3;

±—±-----±-----±-----+

| id | c1 | c2 | c3 |

±—±-----±-----±-----+

| 1 | 1 | cc | 4 |

| 2 | 2 | dd | 5 |

| 4 | 3 | new | 8 |

±—±-----±-----±-----+

3 rows in set (0.00 sec)

复制代码

可以看到原有id=3,c1=3的记录不见了,新增了一条id=4,c1=3的记录.

replace into语句执行完会返回一个数,来指示受影响的行的数目。该数是被删除和被插入的行数的和,上面的例子中2 rows affected .

三、insert on duplicate key update

如果在insert into 语句末尾指定了on duplicate key update,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则在出现重复值的行执行UPDATE;如果不会导致重复的问题,则插入新行,跟普通的insert into一样。

使用insert into,你必须具有insert和update权限

如果有新记录被插入,则受影响行的值显示1;如果原有的记录被更新,则受影响行的值显示2;如果记录被更新前后值是一样的,则受影响行数的值显示0

Case:

复制代码

root:test> show create table t3\G

*************************** 1. row ***************************

Table: t3

Create Table: CREATE TABLE t3 (

id int(11) NOT NULL AUTO_INCREMENT,

c1 int(11) DEFAULT NULL,

c2 varchar(20) DEFAULT NULL,

c3 int(11) DEFAULT NULL,

PRIMARY KEY (id),

UNIQUE KEY uidx_c1 (c1)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

1 row in set (0.00 sec)

root:test> select * from t3;

±—±-----±-----±-----+

| id | c1 | c2 | c3 |

±—±-----±-----±-----+

| 1 | 1 | fds | 4 |

| 2 | 2 | ytu | 3 |

| 3 | 3 | czx | 5 |

±—±-----±-----±-----+

3 rows in set (0.00 sec)

复制代码

插入一条与记录id=3存在唯一键(列c1)冲突的数据

复制代码

root:test> insert into t3(c1,c2,c3) values (3,‘new’,5) on duplicate key update c1=c1+3;

Query OK, 2 rows affected (0.01 sec)

root:test> select * from t3;

±—±-----±-----±-----+

| id | c1 | c2 | c3 |

±—±-----±-----±-----+

| 1 | 1 | fds | 4 |

| 2 | 2 | ytu | 3 |

| 3 | 6 | czx | 5 |

±—±-----±-----±-----+

3 rows in set (0.00 sec)

复制代码

可以看到,id=3的记录发生了改变,c1=原有的c1+3,其他列没有改变。

结论:

这三种方法都能避免主键或者唯一索引重复导致的插入失败问题。

insert ignore能忽略重复数据,只插入不重复的数据。

replace into和insert … on duplicate key update,都是替换原有的重复数据,区别在于replace into是删除原有的行后,在插入新行,如有自增id,这个会造成自增id的改变;insert … on duplicate key update在遇到重复行时,会直接更新原有的行,具体更新哪些字段怎么更新,取决于update后的语句。

分割线分割线分割线分割线分割线分割线分割线分割线

我们在实际业务场景中,经常会有一个这样的需求,插入某条记录,如果已经存在了则更新它如果更新日期或者某些列上的累加操作等,我们肯定会想到使用INSERT … ON DUPLICATE KEY UPDATE语句,一条语句就搞定了查询是否存在和插入或者更新这几个步骤,但是使用这条语句在msyql的innodb5.0以上版本有很多的陷阱,即有可能导致death lock死锁也有可能导致主从模式下的replication产生数据不一致。

正文

正如前言说的那样,在实际业务中,曾经有过一个需求就是插入一条业务数据,如果不存在则新增,存在则累加更新某一个字段的值,于是乎就想到了使用insert… on duplicate key update这个语句,但是有一天去测试环境查看错误日志时,却发现了在多个事务并发执行同一条insert…on duplicate key update 语句时,也就是insert的内容相同时,发生 了死锁。

对于insert…on duplicate key update这个语句会引发dealth lock问题,官方文档也没有相关描述,只是进行如下描述:

An INSERT … ON DUPLICATE KEY UPDATE statement against a table having more than one unique or primary key is also marked as unsafe. (Bug #11765650, Bug #58637)

也就是如果一个表定义有多个唯一键或者主键时,是不安全的,这又引发了以一个问题,见https://bugs.mysql.com/bug.php?id=58637

也就是

当mysql执行INSERT ON DUPLICATE KEY的 INSERT时,存储引擎会检查插入的行是否会产生重复键错误。如果是的话,它会将现有的

行返回给mysql,mysql会更新它并将其发送回存储引擎。当表具有多个唯一或主键时,此语句对存储引擎检查密钥的顺序非常敏感。根据这个顺序,

存储引擎可以确定不同的行数据给到mysql,因此mysql可以更新不同的行。存储引擎检查key的顺序不是确定性的。例如,InnoDB按照索引添加到

表的顺序检查键。首先检查第一个添加的索引。

所以,如果主站和从站按不同的顺序添加索引,那么如果主从复制是基于语句的复制,那么可能最后同一个语句在master上执行和slaver上执行的

结果不一致.

回到死锁的问题

insert … on duplicate key 在执行时,innodb引擎会先判断插入的行是否产生重复key错误,如果存在,在对该现有的行加上S(共享锁)锁,如果返回该行数据给mysql,然后mysql执行完duplicate后的update操作,然后对该记录加上X(排他锁),最后进行update写入。

如果有两个事务并发的执行同样的语句,那么就会产生death lock,如:

解决办法:

1、尽量对存在多个唯一键的table使用该语句

2、在有可能有并发事务执行的insert 的内容一样情况下不使用该语句

on duplicate mysql_mysql 避免重复写入数据的三种方式 和insert ...on duplicate updt... 死锁...相关推荐

  1. MySQL忽略主键冲突,避免重复插入数据的三种方式

    方案一:ignore 插入时检索主键列表,如存在相同主键记录,不更改原纪录,只插入新的记录. INSERT IGNORE INTO ignore关键字所修饰的SQL语句执行后,在遇到主键冲突时会返回一 ...

  2. mysql如何防止插入重复数据_防止MySQL重复插入数据的三种方法

    新建表格 CREATE TABLE `person` ( `id` int NOT NULL COMMENT '主键', `name` varchar(64) CHARACTER SET utf8 C ...

  3. mysql 禁止插入重复数据_防止MySQL重复插入数据的三种方法

    新建表格 CREATE TABLE `person` ( `id` int NOT NULL COMMENT '主键', `name` varchar(64) CHARACTER SET utf8 C ...

  4. android sqlite使用之模糊查询数据库数据的三种方式

    android sqlite使用之模糊查询数据库数据的三种方式 android应用开发中常常需要记录一下数据,而在查询的时候如何实现模糊查询呢?很少有文章来做这样的介绍,所以这里简单的介绍下三种sql ...

  5. 【Java基础】IO流概述分类、字节流写数据、字节流写数据的三种方式及写数据的两个小问题

    目录 一.IO流概述和分类 二.字节流写数据 三.字节流写数据的三种方式 四.字节流写数据的两个小问题 一.IO流概述和分类 IO流介绍: ● IO:输入/输出(Input/Output) ● 流:是 ...

  6. discard connection丢失数据_python kafka 生产者发送数据的三种方式

    python kafka 生产者发送数据的三种方式 发送方式 同步发送 发送数据耗时最长 有发送数据的状态,不会丢失数据,数据可靠性高 以同步的方式发送消息时,一条一条的发送,对每条消息返回的结果判断 ...

  7. layui根据条件显示列_templet渲染layui表格数据的三种方式

    layui前端框架是我一直在使用,也很好用. 今天记录一下,templet渲染layui表格数据的三种方式. 第一种:直接渲染(对于表格数据样式要求不高) 直接在动态表格字段声明,添加templet属 ...

  8. ios网络学习------4 UIWebView的加载本地数据的三种方式

    ios网络学习------4 UIWebView的加载本地数据的三种方式 分类: IOS2014-06-27 12:56 959人阅读 评论(0) 收藏 举报 UIWebView是IOS内置的浏览器, ...

  9. python读取图像数据流_浅谈TensorFlow中读取图像数据的三种方式

    本文面对三种常常遇到的情况,总结三种读取数据的方式,分别用于处理单张图片.大量图片,和TFRecorder读取方式.并且还补充了功能相近的tf函数. 1.处理单张图片 我们训练完模型之后,常常要用图片 ...

  10. layui 表格内容写temple函数_templet渲染layui表格数据的三种方式

    layui前端框架是我一直在使用,也很好用. 今天记录一下,templet渲染layui表格数据的三种方式. 第一种:直接渲染(对于表格数据样式要求不高) 直接在动态表格字段声明,添加templet属 ...

最新文章

  1. 网络安全 — 安全架构
  2. Python列表函数方法
  3. 【Python】相当全面的Pandas文本数据处理,干货多多
  4. C#中利用反射循环给一些字段赋值
  5. openssl java aes_Java AES算法和OpenSSL配对
  6. php基础小结,PHP基础学习小结
  7. ganglia-Monitor
  8. C/C++判断操作系统(Win10,Win8.1WinServer等等)-完整源码及思路
  9. Jquery需要掌握的技巧
  10. exchange 2010 relay设定
  11. demo10 关于JS Tree Shaking
  12. [LeetCode] 100. Same Tree Java
  13. 实习踩坑之路:ElasticSearch双写数据不同步?不实时?怎么优化?
  14. 如何扩展/删除swap分区
  15. 全套思源黑体合集(含ttf/ttc版/行高修正版)
  16. 常见水果日文名称整理:
  17. Linux驱动 | DS18B20驱动编程
  18. (一)SLAM拓扑地图(地图的生成和显示)
  19. 用虚数i与欧拉公式来解释分数阶微积分
  20. 游戏电影——《落花辞》

热门文章

  1. 关于变压器的这些小知识
  2. k60正交解码FTM1 FTM2 困惑
  3. 苹果计算机音频无法使用,苹果电脑没声音了怎么回事
  4. 【BZOJ3991】【SDOI2015】寻宝游戏
  5. Nuvoton_N76E003使用教程
  6. Python爬虫简介
  7. SAP 金额等负号提前问题
  8. 谈谈那些基础但不简单的股票数据
  9. 增加关键词密度不要堆积
  10. 用python证明给定范围的欧拉常数