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...ON DUPLICATE KEY UPDATE产生deathlock
  1. insert ... on duplicate key 在执行时,innodb引擎会先判断插入的行是否产生重复key错误,
  2. 如果存在,在对该现有的行加上S(共享锁)锁,如果返回该行数据给mysql,然后mysql执行完duplicate后的update操作,
  3. 然后对该记录加上X(排他锁),最后进行update写入。
  4.  
  5. 如果有两个事务并发的执行同样的语句,
  6. 那么就会产生death lock,如:

  1. 解决办法:
  2.  
  3. 1、尽量对存在多个唯一键的table使用该语句
  4.  
  5. 2、在有可能有并发事务执行的insert 的内容一样情况下不使用该语句
 

结论:

  • 这三种方法都能避免主键或者唯一索引重复导致的插入失败问题。
  • insert ignore能忽略重复数据,只插入不重复的数据。
  • replace into和insert ... on duplicate key update,都是替换原有的重复数据,区别在于replace into是删除原有的行后,在插入新行,如有自增id,这个会造成自增id的改变;insert ... on duplicate key update在遇到重复行时,会直接更新原有的行,具体更新哪些字段怎么更新,取决于update后的语句。

参考来源:https://www.cnblogs.com/prayer21/p/6018864.html

参考来源:https://www.2cto.com/database/201711/695662.html

MySQL避免插入重复记录:唯一性约束的更多相关文章

  1. mysql 实现多列唯一性约束

    alter table j_assistants add constraint unique_name_course_class unique(name_id,course_id,class_id);

  2. mysql主键约束和唯一性约束

    主键约束和唯一性约束都是索引,它们的区别是: 主键字段可以确保唯一性,但主键字段不能为NULL. 唯一性约束可以确保唯一性,但唯一性约束的字段可以为NULL 唯一性约束对含有NULL的记录不起作用,即 ...

  3. mysql insert if not exists防止插入重复记录的方法(转)

    MySQL 当记录不存在时插入(insert if not exists) 在 MySQL 中,插入(insert)一条记录很简单,但是一些特殊应用,在插入记录前,需要检查这条记录是否已经存在,只有当 ...

  4. Mysql 唯一性约束添加

    来自:  http://blog.csdn.net/yumushui/article/details/38960619 一.单列唯一约束 在一列上添加唯一约束,主要是让该列在表中只能有唯一的一行,例如 ...

  5. Odoo中如何复制有唯一性约束的记录?

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9281393.html  如果为模型的字段添加了唯一性约束,那么在记录的form视图功能菜单上选择“复制”时就会 ...

  6. MySQL 表字段唯一性约束设置方法unique

    1. 建表时加上唯一性约束 CREATE TABLE `t_user` ( `Id` int(11) NOT NULL AUTO_INCREMENT, -- 自增 `username` varchar ...

  7. sqlserver2005唯一性约束

    [转载]http://blog.163.com/rihui_7/blog/static/21228514320136193392749/ 1.设置字段为主键就是一种唯一性约束的方法,如   int p ...

  8. Mysql中unique与primary约束的区别分析(转)

    本文章来给大家介绍在mysql中unique与primary约束的区别分析,unique与primary是我们在创建mysql时常用的类型了,下面我来给大家介绍介绍.   定义了UNIQUE约束的字段 ...

  9. MySQL基础 - 外键和约束

    在工作中经常会遇到不少不同的观点,比如对于数据库来说那就是是否要设置外键,设置外键的理由自然不必多说,而不设置外键的理由多半为设置外键影响性能,但就目前工作来讲,还没有涉及到因为外键而引发的数据库瓶颈 ...

随机推荐

  1. C#文件操作之把字符串取到文本文件及把文本文件读取到字符串中

    一.把字符串读取到文本文件中 using (FileStream fs = new FileStream(Path, FileMode.OpenOrCreate))//把json读到一个文本中 { S ...

  2. python基础08--迭代器,生成器

    1.1 迭代器 1.可迭代对象:str,list,tuple,set,dict, 迭代器:f(文件),range() 可迭代对象和迭代器都可以for循环 可迭代对象不会计数, 迭代器会计数,上面操作到 ...

  3. Prime Path POJ-3126

    The ministers of the cabinet were quite upset by the message from the Chief of Security stating that ...

  4. js new Date()不带时分秒时,时间变了 问题解决

    //先把电脑系统时间的 时区 调到别的时间一下如 夏威夷 UTC-10:00//在浏览器的Console里运行如下代码,getMonth是从0开始的,所以要+1 var d=new Date(&quo ...

  5. js根据json数组多个字段排序

    /**数组根据数组对象中的某个属性值进行排序的方法 * 使用例子:newArray.sort(sortByArr(['number'],false)) //表示根据number属性降序排列;若第二个参 ...

  6. Vue.js前端MVVM框架实战篇

    相信大家对vue.js这个前端框架有了一定的了解.想必也想把Vue急切的运用在项目中,看看它的魅力到底有多大?别急,今天我会满足大家的想法. 我们一起来看看“Webpack+Vue”的开发模式相比以往 ...

  7. Crontab常用命令总结

    一.启动服务 /sbin/service crond start 二.关闭服务 /sbin/service crond stop 三.重启服务 /sbin/service crond restart ...

  8. consul:架构

    官方文档:https://www.consul.io/docs/internals/architecture.html

  9. windows自动化-脚本案例

    ; Script Start - Add your code below here Run("D:\Navicat Premium\navicat.exe") Sleep(1000 ...

  10. xshell链接ubuntu16

    用xshell 链接 ubuntu16 失败 ,是因为没有装 ssh 服务 sudo apt-get install openssh-server         //安装ssh服务 ps -ef | ...