下面我们主要说一下在插入时候的几种情况:

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, '', 'extra 1'), (2, '', 'extra 2'), (3, '', 'extra 3');
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0 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=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, '');
ERROR 1062 (23000): Duplicate entry '' for key 'PRIMARY'
xupeng@diggle8:3600(dba_s) [dba] mysql> REPLACE INTO auto (k, v) VALUES (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相关操作的更多相关文章

  1. MySQL 库、表、记录、相关操作(3)

    MySQL 库.表.记录.相关操作(3) 单表查询 """ 增: insert [into] [数据库名.]表名[(字段1[, ..., 字段n])] values (数 ...

  2. MySQL "replace into" 的坑

    MySQL 对 SQL 有很多扩展,有些用起来很方便,但有一些被误用之后会有性能问题,还会有一些意料之外的副作用,比如 REPLACE INTO. 比如有这样一张表: CREATE TABLE `au ...

  3. [转] MySQL "replace into" 的坑 (5.5 ROW格式)

    MySQL 对 SQL 有很多扩展,有些用起来很方便,但有一些被误用之后会有性能问题,还会有一些意料之外的副作用,比如 REPLACE INTO. 比如有这样一张表: 1 2 3 4 5 6 7 8 ...

  4. MySQL 库、表、记录、相关操作(2)

    库.表.记录.相关操作(2) 字段操作 create table tf1( id int primary key auto_increment, x int, y int ); # 修改 alter ...

  5. MySQL 库、表、记录、相关操作(1)

    库.表.记录.相关操作(1) 数据库配置 # 通过配置文件统一配置的目的:统一管理 服务端(mysqld) .客户端(client) # 配置了 mysqld(服务端) 的编码为utf8,那么再创建的 ...

  6. mysql 5.7 laravel json类型数据相关操作

    2018年10月16日18:14:21 官方文档中文翻译版 原文:https://dev.mysql.com/doc/refman/5.7/en/json.html 最后有部分实例和一个小总结 11. ...

  7. mysql 和mssql2016中的json字段相关操作

    Mysql: mysql中有专门的Json字段,不是通用的varchar字段,可以保存key/value对,也可保存value集合. 可以增加.删除.修改Json中的某一字段,查询时可以为条件. 如果 ...

  8. MySQL(3) - 数据库表的相关操作

    1.数据库表的创建 逻辑库 1)创建逻辑库:CREATE DATABASE 逻辑库名称; 2)显示逻辑库:SHOW DATABASES; 3)删除逻辑库:DROP DATABASE 逻辑库名称; 数据 ...

  9. MySql学习笔记【四、数据相关操作】

    CURD--增改查删 创建数据 INSERT [INTO] tb_name [(col_name,...)] VALUES(val,..) 若列名缺省,表示插入全部列,也可指定部分列名 如: INSE ...

随机推荐

  1. Ubuntu下配置jdk及maven等方法

    从/etc/profile文件代码得知系统启动会把/etc/profile.d目录下面所有的.sh文件进行加载,如果在其中新建.sh文件用来设立环境变量等,系统启动后也会加载到它们.另外一种方法就是修 ...

  2. 翻译记忆软件-塔多思TRADO经典教程_3

    一.创建思迪术语库 1."开始>程序"中打开程序的主界面 2.按窗口内的"术语库"图标,或者"术语库"菜单"维护一个术语库数 ...

  3. WPF 同一个程序 只允许 同时运行一个

            方法2  当程序已经运行了 再运行这个程序时,则显示当前这个窗体  http://code.3rbang.com/cshape-run-one/ VS2013附件:http://fil ...

  4. uva 11181 - Probability|Given(概率)

    题目链接:uva 11181 - Probability|Given 题目大意:有n个人去超市买东西,给出r,每个人买东西的概率是p[i],当有r个人买东西的时候,第i个人恰好买东西的概率. 解题思路 ...

  5. Flume-0.9.4数据插入HBase-0.96

    来自:http://blog.csdn.net/iam333/article/details/18770977 最近由于业务需要,需要将flume的数据插入HBase-0.96,利用flume的实时日 ...

  6. Springboot UT 引入某些类

    http://www.infoq.com/cn/articles/Unit-Testing-Complete-Integration-Testing-Begins https://segmentfau ...

  7. Java编程思想(十五) —— 类型信息之反射

    讲完.class,Class之后,继续. 1)泛化的Class引用 Class也能够增加泛型,增加之后会进行类型检查. 贴一下书上原话,Class<?>优于Class,尽管他们是等价的,C ...

  8. java Properties的用法

    Properties是一个特殊的Map,因为和IO流牵扯到了一块…… import java.io.BufferedReader;import java.io.File;import java.io. ...

  9. [Table] pm_result

    ', '20160501.17:30 - 20160501.17:45', '2.1', '3.1', '3.1', '3.11', '3.44', '12.30', null, null, null ...

  10. 【zend studio】如何添加已存在的git项目

    1.在zend里面新增项目crm2 2.win下进入crm2目录,右键选择 Git Bash Here,进项git clone操作 3.进入下载下来的GIT项目目录,选择复制,然后返回上一目录crm2 ...