如果表中定义了唯一索引,而我们插入记录要避免违反这个约束,该怎么弄?

最原始的办法,是先查找一下,确认不违反,才插入。现在都用ORM框架来操作数据库,搞不好还要分成两个步骤,调用2个方法才能完成。或者搞一个存储过程之类。这种方法繁琐不说,其实还不可靠。在并发的情况下,并不能保证完全不违反约束。

mysql提供了一些语句来处理这种情况。

1、使用 INSERT IGNORE 语句
2、使用 ON DUPLICATE KEY UPDATE 从句
3、使用 REPLACE 语句

假设我们有一个用户表,user_id是主键,则user_id具有唯一约束。

+---------+------------+-----------+
| user_id | first_name | last_name |
+---------+------------+-----------+
|     202 | Thor       | Odinson   |
|     204 | Loki       | Laufeyson |
+---------+------------+-----------+
2 rows in set (0.00 sec)

现在要新增一个用户

INSERT INTO users 
  (user_id, first_name, last_name) 
VALUES 
  (202, "Tony", "Smith");

由于user_id=202已存在,必然报错:

ERROR 1062 (23000): Duplicate entry '202' for key 'users.PRIMARY'

这时候可以采用以下三种方法之一来处理:

1、使用 INSERT IGNORE 语句

INSERT IGNORE INTO users 
  (user_id, first_name, last_name) 
VALUES 
  (202, "Tony", "Smith");

执行该语句,如果表中不存在user_id=202的记录,则记录插入,和普通的insert没有区别;但如果已经存在,mysql将不插入吗,同时抛出一个警告,但不会导致异常。

2、使用 ON DUPLICATE KEY UPDATE 从句

INSERT INTO users
  (user_id, first_name, last_name) 
VALUES 
  (202, "Tony", "Smith")
ON DUPLICATE KEY UPDATE
  first_name = "Tony",
  last_name = "Smith";

如果不存在冲突,顺利插入;否则用指定的值update冲突记录。

这个语句特别适合无则插入,有则更新的场景。以前我们总是喜欢自己写一些 insertOrUpdate之类的方法,来应付上述情况。办法是先update,看看受影响的记录数是否为0,0的话说明表里没这个记录,于是插入。

3、使用 REPLACE 语句

是ON DUPLICATE KEY UPDATE 从句的替代。但这个方法比较狠,简单粗暴。一旦存在冲突的情况,会先将表里现有记录删掉,然后再插入新的。

REPLACE INTO users
  (user_id, first_name, last_name) 
VALUES
  (202, "Tony", "Smith");

参考文章:
MySQL - How to insert a new row only if data do not exist

MySQL表创建唯一索引,出现报错Duplicate entry * for key. 使用show index from table确认table中并不存在重名的唯一索引名称。 仔细看报错信息,根据那串ID数字,发现是表中出现违反创建的唯一索引键规则的重复数据,将此数据删除后创建唯一索引成功。 ALTER TABLE person ADD UNIQUE `UNI_person_area`(`person_id`, `area_id`) USING BTREE COMMENT "人员重复" insert ignore into insert ignore into(使用唯一索引再次插入相同的值会忽略提示*如果insert into 数据库会报错*,相同值不会插入但id指针会向后跳一位),这样当有重复记录就会忽略,执行后返回数字0。 insert ignore i...
该文为《 MySQL 实战 45 讲》的学习笔记,感谢查看,如有错误,欢迎指正 一、查询和更新上的区别 这两类索引在查询能力上是没差别的,主要考虑的是对更新性能的影响。建议尽量选择普通索引。 1.1 MySQL 的查询操作 查找到第一个满足条件的记录后,继续向后遍历,直到第一个不满足条件的记录。 由于索引定义了唯一性,查找到第一个满足条件的记录后,直接停止继续检索。 普通索引会多检索一次,几乎没有影响。因为 InnoDB 的数据是按照数据页为单位进行读写的,需要读取数据,并不...
1.采用force index 强行选择一个索引。 2.修改sql语句、引导MySQL使用我们期望的索引。 3.在有些场景下,我们可以新建一个更适合的索引,来提供给优化器做选择,或删除掉误用的索引。 由于索引统计信息的不准确,可以用analyze table来解决。 而对于其它优化器误判断的情况,你可以在应用端用force index 来强行指定索引,也可以通过修改语句来引导优化器,还可以通过增加或者删除索引来绕过这个问题。
这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Ma...
|-- java.sql.SQLException |-- SQLNonTransientException |-- SQLIntegrityConstraintViolationException //新增机型 aircraftService.save(aircraft); return R.ok(aircraft.getId()); }catch (Exception e){ Thr..
如数据表 users ,列分别为id,user_name,age,create_at,delete_at 要实现以user_name(用户名)为唯一索引,并支持软删除,以delete_at(删除间)不为空为标识; 同一个表中会存在多条user_name相同的行,与唯一索引冲突; 解决方案: 以 user_name 和 delete_at 建立组合唯一索引 alter table users add unique index uidx(user_name,delete_at); 当dele
迁移到达梦数据库后,发现我们的全局异常拦截中的唯一索引异常 无法被正常拦截,给前端直接抛出了数据库原始的错误信息,对用户极其不友好。如果不对唯一索引异常拦截,则默认 与 的异常信息如下:在 中通过 注解,实现对异常响应的统一封装。可参考:全栈开发之后端脚手架:SpringBoot集成MybatisPlus代码生成,分页,雪花算法,统一响应,异常拦截,Swagger3接口文档以下是对数据库唯一索引异常的拦截,统一返回:编号不可重复。 对主流的数据库的异常进行了封装与翻译,对于 都可以进
gradle版本引起编译报错问题:Cause: org.jetbrains.plugins.gradle.tooling.util.ModuleComponentIdentifierImpl.getM 110235