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基础 - 外键和约束
在工作中经常会遇到不少不同的观点,比如对于数据库来说那就是是否要设置外键,设置外键的理由自然不必多说,而不设置外键的理由多半为设置外键影响性能,但就目前工作来讲,还没有涉及到因为外键而引发的数据库瓶颈 ...
随机推荐
- webpack等bundler是如何工作的-简化版本
webpack- why and how 首先不要被webpack做的复杂花哨的工作所迷惑,到底webpack是个啥?一句话,webpack是一个module bundler(模块打包器).多一句话, ...
- ThreadLocal定义、使用案例及源码分析
原文连接:(http://www.studyshare.cn/blog/details/1165/0 ) 一.ThreadLocal定义 jdk官方文档定义是:该类提供线程局部变量. 这些变量与其正常 ...
- vue打包后页面显示空白但是不报错
在使用vue打包的时候页面显示空白,并且控制台不报错 设置vue-router的时候mode设置为history模式了,这种模式要有后台的配合,一般还是使用哈希模式就不会出现页面空白了.
- 英语bitellos钻石bitellos单词
大颗粒的钻石叫做bitellos,四大钻石指的就是“摄政王”.“南非之星”.“蓝色希望”和“光明之山”四颗钻石.经过琢磨的钻石光彩夺目.灿烂无比,历来被誉为“宝石之王”,科研领域里大颗粒的钻石叫做bi ...
- 干货分享 | 3个开发IoT项目的开源物联网平台
物联网(IoT)是帮助人工智能(AI)以更好的方式控制和理解事物的未来技术. 艾艺收集了一些最有名的物联网平台,帮助您以受控方式开发物联网项目.物联网平台是帮助设置和管理互联网连接设备的组件套件. 一 ...
- python基础-os模块
os 模块 功能:与操作系统交互的模块 使用方式:import os 常用的几种功能 os.path.dirname(文件名) 用于获取当前文件的所在目录 import os # 获取当前文件的所在目 ...
- PB调用C#编写的Dll类库
在c# 中编写com组件,供PB调用实例 前言:c#中写的dll直接是不能被pb调用的,只有写成com组件才可以调用,所以用c#写dll时要注意. c#中新建类库 类库类型为通用类库,项目名为AddC ...
- Ansible入门笔记(2)之常用模块
目录 Ansible常用模块 1.1.Ansible Ad-hoc 1.2.Ansible的基础命令 1.3.常用模块 Ansible常用模块 1.1.Ansible Ad-hoc 什么事ad-hoc ...
- k8s 学习笔记
常用的kubectl命令 kubectl run kubia --image=luksa/kubia --port=8080 --generator=run/v1 --image 指定镜像 - ...
- Nginx的特性功能-反向代理、负载均衡、缓存、动静分离、平滑升级
反向代理 nginx配置文件 events { } 事件驱动 httpd { } 关于httpd相关的配置 server { } 定义虚拟主机 location { } ...