MySQL避免插入重复记录:唯一性约束
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
- insert ... on duplicate key 在执行时,innodb引擎会先判断插入的行是否产生重复key错误,
- 如果存在,在对该现有的行加上S(共享锁)锁,如果返回该行数据给mysql,然后mysql执行完duplicate后的update操作,
- 然后对该记录加上X(排他锁),最后进行update写入。
- 如果有两个事务并发的执行同样的语句,
- 那么就会产生death lock,如:
- 解决办法:
- 1、尽量对存在多个唯一键的table使用该语句
- 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避免插入重复记录:唯一性约束的更多相关文章
- mysql 实现多列唯一性约束
alter table j_assistants add constraint unique_name_course_class unique(name_id,course_id,class_id);
- mysql主键约束和唯一性约束
主键约束和唯一性约束都是索引,它们的区别是: 主键字段可以确保唯一性,但主键字段不能为NULL. 唯一性约束可以确保唯一性,但唯一性约束的字段可以为NULL 唯一性约束对含有NULL的记录不起作用,即 ...
- mysql insert if not exists防止插入重复记录的方法(转)
MySQL 当记录不存在时插入(insert if not exists) 在 MySQL 中,插入(insert)一条记录很简单,但是一些特殊应用,在插入记录前,需要检查这条记录是否已经存在,只有当 ...
- Mysql 唯一性约束添加
来自: http://blog.csdn.net/yumushui/article/details/38960619 一.单列唯一约束 在一列上添加唯一约束,主要是让该列在表中只能有唯一的一行,例如 ...
- Odoo中如何复制有唯一性约束的记录?
转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9281393.html 如果为模型的字段添加了唯一性约束,那么在记录的form视图功能菜单上选择“复制”时就会 ...
- MySQL 表字段唯一性约束设置方法unique
1. 建表时加上唯一性约束 CREATE TABLE `t_user` ( `Id` int(11) NOT NULL AUTO_INCREMENT, -- 自增 `username` varchar ...
- sqlserver2005唯一性约束
[转载]http://blog.163.com/rihui_7/blog/static/21228514320136193392749/ 1.设置字段为主键就是一种唯一性约束的方法,如 int p ...
- Mysql中unique与primary约束的区别分析(转)
本文章来给大家介绍在mysql中unique与primary约束的区别分析,unique与primary是我们在创建mysql时常用的类型了,下面我来给大家介绍介绍. 定义了UNIQUE约束的字段 ...
- MySQL基础 - 外键和约束
在工作中经常会遇到不少不同的观点,比如对于数据库来说那就是是否要设置外键,设置外键的理由自然不必多说,而不设置外键的理由多半为设置外键影响性能,但就目前工作来讲,还没有涉及到因为外键而引发的数据库瓶颈 ...
随机推荐
- C#里面如何判断一个Object是否是某种类型
第一种方法 var isA = oldObject.GetType() == typeof(Dictionary<string, string>) 第二种方法 var isB = oldO ...
- 灰度共生矩阵(Gray-level Co-occurrence Matrix,GLCM),矩阵的特征量
又叫做灰度共现矩阵 Prerequisites 概念 计算方式 对于精度要求高且纹理细密的纹理分布,我们取像素间距为d=1d=1,以下是方向的说明: 我们来看,matlab内置工具箱中的灰度共生矩阵的 ...
- Java自学-日期 Date
Java的日期类Date Date类 注意:是java.util.Date; 而非 java.sql.Date,此类是给数据库访问的时候使用的 示例 1 : 时间原点概念 所有的数据类型,无论是整数, ...
- Jenkins+Gitee异常解决
Failed to connect to repository : Command "git ls-remote -h username@mygit.com:cc/myproject.git ...
- 从 html 元素继承 box-sizing
在大多数情况下我们在设置元素的 border 和 padding 并不希望改变元素的 width,height值,这个时候我们就可以为该元素设置 box-sizing:border-box;. 我不希 ...
- 编写可维护的JavaScript-随笔(四)
避免使用全局变量 一.全局变量带来的问题 a) 命名冲突 i. 当全局变量和全局函数越来越多时,发生命名冲突的概率也随之增高 ii. 如果函数中使用了外部 ...
- HTTP 强制缓存和协商缓存
Web 缓存能够减少延迟与网络阻塞,进而减少显示某个资源所用的时间.借助 HTTP 缓存,Web 站点变得更具有响应性. 缓存优点: 减少不必要的数据传输,节省带宽 减少服务器负担,提升网站性能 加快 ...
- Python 短路机制
And / Or A B A and B A or B Not A True True True True False True False False True False False True F ...
- Httpd服务入门知识-Httpd服务常见配置案例之定义站点主页面及错误页面配置
Httpd服务入门知识-Httpd服务常见配置案例之定义站点主页面及错误页面配置 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.定义站点主页面 [root@node101.yi ...
- python的包管理软件Conda的用法
创建自己的虚拟环境 conda create -n learn python= 切换环境: activate learn 查看所有环境: conda env list 安装第三方包: conda in ...