MySQL replace into 的坑以及insert相关操作
下面我们主要说一下在插入时候的几种情况:
1:insert ignore
2:replace into
3:ON DUPLICATE KEY UPDATE
关于insert ignore:
关于replace into:
关于ON DUPLICATE KEY UPDATE :
MySQL 对 SQL 有很多扩展,有些用起来很方便,但有一些被误用之后会有性能问题,还会有一些意料之外的副作用,比如 REPLACE INTO。
比如有这样一张表:
CREATE TABLE `auto` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`k` int(10) unsigned NOT NULL,`v` varchar(100) DEFAULT NULL,`extra` varchar(200) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `uk_k` (`k`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1
auto 表有一个自增的 id 字段作为主键,字段 k 有 UNIQUE KEY 做唯一性约束。写入几条记录之后会是这样:
xupeng@diggle7:3600(dba_m) [dba] mysql> INSERT INTO auto (k, v, extra) VALUES (1, '1', 'extra 1'), (2, '2', 'extra 2'), (3, '3', 'extra 3'); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0xupeng@diggle7:3600(dba_m) [dba] mysql> SHOW CREATE TABLE auto\G *************************** 1. row ***************************Table: auto Create Table: CREATE TABLE `auto` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`k` int(10) unsigned NOT NULL,`v` varchar(100) DEFAULT NULL,`extra` varchar(200) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `uk_k` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 1 row in set (0.01 sec)xupeng@diggle7:3600(dba_m) [dba] mysql> SELECT * FROM auto; +----+---+------+---------+ | id | k | v | extra | +----+---+------+---------+ | 1 | 1 | 1 | extra 1 | | 2 | 2 | 2 | extra 2 | | 3 | 3 | 3 | extra 3 | +----+---+------+---------+ 3 rows in set (0.00 sec)
在 slave 节点上是和 master 一致的:
xupeng@diggle8:3600(dba_s) [dba] mysql> SELECT * FROM auto; +----+---+------+---------+ | id | k | v | extra | +----+---+------+---------+ | 1 | 1 | 1 | extra 1 | | 2 | 2 | 2 | extra 2 | | 3 | 3 | 3 | extra 3 | +----+---+------+---------+ 3 rows in set (0.00 sec)xupeng@diggle8:3600(dba_s) [dba] mysql> SHOW CREATE TABLE auto\G *************************** 1. row ***************************Table: auto Create Table: CREATE TABLE `auto` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`k` int(10) unsigned NOT NULL,`v` varchar(100) DEFAULT NULL,`extra` varchar(200) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `uk_k` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 1 row in set (0.00 sec)
可以看到,写入三条记录之后,auto 表的 AUTO_INCREMENT 增长为 4,也就是说下一条不手工为 id 指定值的记录,id 字段的值会是 4。
接下来使用 REPLACE INTO 来写入一条记录:
xupeng@diggle7:3600(dba_m) [dba] mysql> REPLACE INTO auto (k, v) VALUES (1, '1-1'); Query OK, 2 rows affected (0.01 sec)xupeng@diggle7:3600(dba_m) [dba] mysql> SELECT * FROM auto; +----+---+------+---------+ | id | k | v | extra | +----+---+------+---------+ | 2 | 2 | 2 | extra 2 | | 3 | 3 | 3 | extra 3 | | 4 | 1 | 1-1 | NULL | +----+---+------+---------+ 3 rows in set (0.00 sec)xupeng@diggle7:3600(dba_m) [dba] mysql> SHOW CREATE TABLE auto\G *************************** 1. row ***************************Table: auto Create Table: CREATE TABLE `auto` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`k` int(10) unsigned NOT NULL,`v` varchar(100) DEFAULT NULL,`extra` varchar(200) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `uk_k` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 1 row in set (0.00 sec)
可以看到 MySQL 说 “2 rows affected”,可是明明是只写一条记录,为什么呢?这是因为 MySQL 在执行 REPLACE INTO auto (k) VALUES (1) 时首先尝试 INSERT INTO auto (k) VALUES (1),但由于已经存在一条 k=1 的记录,发生了 duplicate key error,于是 MySQL 会先删除已有的那条 k=1 即 id=1 的记录,然后重新写入一条新的记录。
这时候 slave 上出现了诡异的问题:
xupeng@diggle8:3600(dba_s) [dba] mysql> SHOW CREATE TABLE auto\G *************************** 1. row ***************************Table: auto Create Table: CREATE TABLE `auto` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`k` int(10) unsigned NOT NULL,`v` varchar(100) DEFAULT NULL,`extra` varchar(200) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `uk_k` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
可以知道,当前表内数据 id 字段的最大值是 4,AUTO_INCREMENT 应该为 5,但在 slave 上 AUTO_INCREMENT 却并未更新,这会有什么问题呢?把这个 slave 提升为 master 之后,由于 AUTO_INCREMENT 比实际的 next id 还要小,写入新记录时就会发生 duplicate key error,每次冲突之后 AUTO_INCREMENT += 1,直到增长为 max(id) + 1 之后才能恢复正常:
xupeng@diggle8:3600(dba_s) [dba] mysql> REPLACE INTO auto (k, v) VALUES (4, '4'); ERROR 1062 (23000): Duplicate entry '4' for key 'PRIMARY' xupeng@diggle8:3600(dba_s) [dba] mysql> REPLACE INTO auto (k, v) VALUES (5, '5'); Query OK, 1 row affected (0.00 sec)xupeng@diggle8:3600(dba_s) [dba] mysql> SELECT * FROM auto; +----+---+------+---------+ | id | k | v | extra | +----+---+------+---------+ | 2 | 2 | 2 | extra 2 | | 3 | 3 | 3 | extra 3 | | 4 | 1 | 1-1 | NULL | | 5 | 5 | 5 | NULL | +----+---+------+---------+ 4 rows in set (0.00 sec)
没有预料到 MySQL 在数据冲突时实际上是删掉了旧记录,再写入新记录,这是使用 REPLACE INTO 时最大的一个误区,拿之前的例子来说,执行完 REPLACE INTO auto (k, v) VALUES (1, ‘1-1’) 之后,由于新写入记录时并未给 extra 字段指定值,原记录 extra 字段的值就「丢失」了,而通常这并非是业务上所预期的,更常见的需求实际上是,当存在 k=1 的记录时,就把 v 字段的值更新为 ‘1-1’,其他未指定的字段则保持原状,而满足这一需求的 MySQL 方言是 INSERT INTO auto (k, v) VALUES (1, ‘1-1’) ON DUPLICATE KEY UPDATE v=VALUES(v);
鉴于此,很多使用 REPLACE INTO 的场景,实际上需要的是 INSERT INTO … ON DUPLICATE KEY UPDATE,在正确理解 REPLACE INTO 行为和副作用的前提下,谨慎使用 REPLACE INTO。
参考:
https://blog.xupeng.me/2013/10/11/mysql-replace-into-trap/
https://9iphp.com/web/php/mysql-on-duplicate-key-update.html
MySQL replace into 的坑以及insert相关操作相关推荐
- mysql 数据表内容_mysql数据库内容相关操作
第一:介绍 mysql数据内容的操作主要是: INSERT实现数据的插入 UPDATE实现数据的更新 DLETE实现数据的删除 SELECT实现数据的查询. 第二:增(insert) 1.插入完整的数 ...
- mysql在cmd命令行下的相关操作
1.设置新的root密码. mysql -u root -p 直接回车,无需输入密码就可以进入数据库了. 此时在命令行下执行 use mysql (切换到系统数据库) 执行以下语句既可修改root用户 ...
- mysql replace报错_Mysql中replace与replace into的用法讲解
Mysql replace与replace into都是经常会用到的功能:replace其实是做了一次update操作,而不是先delete再insert:而replace into其实与insert ...
- MySQL:讨人喜欢的 MySQL replace into 用法(insert into 的增强版)
讨人喜欢的 MySQL replace into 用法(insert into 的增强版) 在向表中插入数据的时候,经常遇到这样的情况:1. 首先判断数据是否存在: 2. 如果不存在,则插入:3.如果 ...
- MariaDB/MySQL防止重复插入相同记录:INSERT IGNORE或者REPLACE
MySQL防止重复插入相同记录有2种常用的方法. 1 使用 INSERT IGNORE 使用 INSERT IGNORE 可以在插入具有相同主键的数据时不做重复插入. mysql> SELECT ...
- insert 语句_替换某字段中的特定字符串——MySQL REPLACE 与INSERT 函数详解
MySQL提供了一个非常实用的字符串函数--REPLACE() 函数,它允许用新的字符串替换字段中的特定字符串,而不再需要自己写函数去替换,用起来非常的方便. REPLACE() 函数语法 需要注意的 ...
- mysql insert replace_mysql 操作总结 INSERT和REPLACE
--他人总结的 用于操作数据库的SQL一般分为两种,一种是查询语句,也就是我们所说的SELECT语句,另外一种就是更新语句,也叫做数据操作语句. 言外之意,就是对数据进行修改.在标准的SQL中有3个语 ...
- MySQL replace into (insert into 的增强版)
在使用SQL语句进行数据表插入insert操作时,如果表中定义了主键,插入具有相同主键的记录会报错: Error Code: 1062. Duplicate entry 'XXXXX' for ke ...
- MySQL 当记录不存在时insert,当记录存在时update(ON DUPLICATE KEY UPDATE, REPLACE语句)...
MySQL 当记录不存在时insert,当记录存在时更新 网上基本有三种解决方法. 第一种:示例一:insert多条记录 假设有一个主键为 client_id 的 clients 表,可以使用下面的语 ...
最新文章
- dnf拍卖行计算机在线,DNF助手拍卖行在哪里 拍卖行物价实时查询
- oracle executesqlcommand,Oracle Execute Command Sql Script in Win
- 神策数据荣膺“2017 年度最受欢迎企业服务商 Top 10”
- Linux 小知识翻译 - 「单CD 的linux」
- scrapy-redis爬虫如何发送POST请求
- 安装ISA2004后,加入域时提示:远程过程调用失败且未运行的解决办法
- ImageLoader的简单分析(终结篇)
- OSSIM安装zabbix
- 重磅!Spring Cloud 生态再添新套件:Spring Cloud Tencent
- MybatisPlus学习笔记
- radon变换(c++、OpenCV实现)
- 吐槽国内各大公司的漏洞报告平台
- latex 两行 大括号_用laTeX排版大括号的三种方法
- 从事热爱的工作和积极乐观
- 盲盒App就是一元购吗?
- Linux 2.6下Driver开发的34个变化[转贴]
- 性能测试中怎么检测CPU情况
- iOS8 对开发人员来说意味着什么?
- 优盘格式化了怎么恢复里面的数据?
- 《洋妞》万像电影节揽四奖 或打造同名综艺节目