前段时间写游戏合服工具时出现过一个问题,源DB和目标DB角色表中主键全部都不相同,从源DB取出玩家数据再使用 replace into 写入目标DB中,结果总有几条数据插入时会导致目标DB中原有的角色数据丢失了。仔细排查之后发现时replace into使用错误造成的。在这里总结下replace into的使用方式,可以帮助有幸看到这篇文章的朋友避开replace into 使用的坑。

 

replace into 执行流程

1. 尝试向表中插入新行

2. 插入失败,因为表中存在相同的主键或唯一索引
   
    a.删除表中所有相同的主线以及唯一索引的记录
   
    b.再次尝试向表中插入新行
 

与insert的区别

insert是直接插入记录,如果表中存在相同的主键或唯一索引,插入失败。

 
replace into也是插入记录,如果表中存在相同的主键或唯一索引,先删除相同主键或唯一索引记录,再执行插入操作。如果表中不存在相同主键或唯一索引时,和insert时相同的。
 

注意

1. 使用replace into时需要对表有delete和insert的权限
2. replace into语句中所有缺失的字段都会被设置为字段的默认值
3. replace into执行记结果受影响的行数大于1行时,插入操作只有一行受影响,其他受影响的行是删除操作
4. replace..set col_name = col_name + 1时,col_name会被当做默认值,赋值最终等价于 col_name = DEFAULT(col_name) + 1
 
 
假如有如下的表:
mysql> show create table test\G
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`id` int(11) NOT NULL,
`name` char(32) NOT NULL,
`uid` int(11) NOT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_name` (`name`),
KEY `idx_uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec) mysql> replace into test(id,name,uid,age) values(1,'aa',101,20),(2,'bb',102,21);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from test;
+----+------+-----+------+
| id | name | uid | age |
+----+------+-----+------+
| 1 | aa | 101 | 20 |
| 2 | bb | 102 | 21 |
+----+------+-----+------+
2 rows in set (0.00 sec)

现在执行下面的操作:

mysql> replace into test(id,name,uid,age) values(2,'cc',103,22);
Query OK, 2 rows affected (0.00 sec)
mysql> select * from test;
+----+------+-----+------+
| id | name | uid | age |
+----+------+-----+------+
| 1 | aa | 101 | 20 |
| 2 | cc | 103 | 22 |
+----+------+-----+------+
2 rows in set (0.00 sec)

replace into语句执行之后,2行受影响,主键id=2在表中已经存在,先删除表中主键,然后再插入新行数据

mysql> select * from test;
+----+------+-----+------+
| id | name | uid | age |
+----+------+-----+------+
| 1 | aa | 101 | 20 |
| 2 | cc | 103 | 22 |
+----+------+-----+------+
2 rows in set (0.00 sec)
mysql> replace into test(id,name,uid,age) values(2,'aa',100,25);
Query OK, 3 rows affected (0.02 sec)
mysql> select * from test;
+----+------+-----+------+
| id | name | uid | age |
+----+------+-----+------+
| 2 | aa | 100 | 25 |
+----+------+-----+------+
1 row in set (0.00 sec)
 
replace into语句执行之后,3行受影响,主键id=2在表中已经存在,先删除表中主键行,唯一索引name='aa'再表中已经存在,先删除表中索引行,然后再插入新行数据
 
mysql> replace into test(id,name,uid,age) values(3,'dd',100,25);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test;
+----+------+-----+------+
| id | name | uid | age |
+----+------+-----+------+
| 2 | aa | 100 | 25 |
| 3 | dd | 100 | 25 |
+----+------+-----+------+
2 rows in set (0.01 sec)
 
replace into语句执行之后,1行受影响,表中没有相同的主键以及唯一索引相同,uid字段是普通索引,不是唯一索引,所以不会有删除操作,最终和insert语句效果一样,插入一行新数据
 
mysql> replace into test set id = 3,name='dd',uid=100,age=age+1;
Query OK, 2 rows affected (0.01 sec)
mysql> select * from test;
+----+------+-----+------+
| id | name | uid | age |
+----+------+-----+------+
| 2 | aa | 100 | 25 |
| 3 | dd | 100 | NULL |
+----+------+-----+------+
2 rows in set (0.00 sec)
mysql> select NULL + 1;
+----------+
| NULL + 1 |
+----------+
| NULL |
+----------+
1 row in set (0.00 sec)
mysql> update test set age = age + 1 where id = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from test;
+----+------+-----+------+
| id | name | uid | age |
+----+------+-----+------+
| 2 | aa | 100 | 26 |
| 3 | dd | 100 | NULL |
+----+------+-----+------+
2 rows in set (0.00 sec)
 
 
如果使用 replace...set col_name = col_name + 1 语句的话,col_name取的是默认值,这里age的默认值是NULL,set age = age + 1 等价于 set age = NULL + 1,结果还是为NULL
 
使用update...set col_name = col_name + 1就不会有这个问题,这里的主要原因是 replace 会先删除重复主键或唯一索引的记录,再插入一行新数据,当删除原有数据之后 age 字段就没有值了。所以这里的 replace ...set age = age + 1,age 的最终值是NULL,我们修改下age的默认值,再执行replace...set age = age + 1看下结果
 
mysql> select * from test;
+----+------+-----+------+
| id | name | uid | age |
+----+------+-----+------+
| 2 | aa | 100 | 26 |
| 3 | dd | 100 | NULL |
+----+------+-----+------+
2 rows in set (0.00 sec)
mysql> alter table test alter age set default 3;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> replace into test set id = 2,name='aa',uid=100,age = age + 1;
Query OK, 2 rows affected (0.07 sec)
mysql> select * from test;
+----+------+-----+------+
| id | name | uid | age |
+----+------+-----+------+
| 2 | aa | 100 | 4 |
| 3 | dd | 100 | NULL |
+----+------+-----+------+
2 rows in set (0.00 sec)
把age的默认值修改成3之后,执行replace..set age = age + 1, age最终的值不在是NULL了。
 

MySQL REPLACE INTO 的使用的更多相关文章

  1. MySQL replace into 使用详解 及 注意事项

    REPLACE的运行与INSERT很相似.只有一点例外,假如表中的一个旧记录与一个用于PRIMARY KEY或一个UNIQUE索引的新记录具有相同的值,则在新记录被插入之前,旧记录被删除.注意:除非表 ...

  2. MySQL replace函数替换字符串语句的用法(mysql字符串替换)

    MySQL replace函数我们经常用到,下面就为您详细介绍MySQL replace函数的用法,希望对您学习MySQL replace函数方面能有所启迪. 最近在研究CMS,在数据转换的时候需要用 ...

  3. MySQL "replace into" 的坑

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

  4. MySQL replace into 说明(insert into 增强版)

    MySQL replace into 说明(insert into 增强版) 在插入数据到一个表时,通常是这种情况:1. 先推断数据是否存在: 2. 假设不存在,则插入:3.假设存在,则更新. 在 S ...

  5. MySQL replace into (insert into 的增强版)

    在使用SQL语句进行数据表插入insert操作时,如果表中定义了主键,插入具有相同主键的记录会报错:  Error Code: 1062. Duplicate entry 'XXXXX' for ke ...

  6. mysql replace into 的使用情况

    replace into的存在的几种情况 当表存在主键并且存在唯一键的时候 如果只是主键冲突 mysql> select * from auto; +----+---+------+------ ...

  7. 细说mysql replace into

    replace语句在一般的情况下和insert差不多,但是如果表中存在primary 或者unique索引的时候,如果插入的数据和原来的primary key或者unique相同的时候,会删除原来的数 ...

  8. Mysql replace into

    mysqlsql serverinsert 在向表中插入数据的时候,经常遇到这样的情况:1. 首先判断数据是否存在: 2. 如果不存在,则插入:3.如果存在,则更新. 在 SQL Server 中可以 ...

  9. MySQL "replace into" 的坑以及insert相关操作

    下面我们主要说一下在插入时候的几种情况: 1:insert ignore 2:replace into 3:ON DUPLICATE KEY UPDATE 关于insert ignore: 关于rep ...

  10. MySQL replace into 用法

    讨人喜欢的 MySQL replace into 用法(insert into 的增强版) 在向表中插入数据的时候,经常遇到这样的情况:1. 首先判断数据是否存在: 2. 如果不存在,则插入:3.如果 ...

随机推荐

  1. try_catch_return

    1.情况一(try中有return,finally中没有return): public class TryTest{ public static void main(String[] args){ S ...

  2. SQL常见错误总结

    目录 语法错误 标点错漏 重命名 数据拼接 null值 逻辑顺序 函数错误 参数的数量 参数的格式 逻辑错误 数据重复 无效筛选 标签重叠 时间错位 SQL是数据分析中最高频的操作之一,本文梳理常见的 ...

  3. 项目总结&读书笔记

    Python项目 01-函数版ATM 读书笔记 01-Effective Python

  4. [前端开发]Vue组件化的思想

    组件化的思想 将一个页面中的处理逻辑放在一起,处理起来就会很复杂,不利于后续管理和扩展. 如果将页面拆分成一个个小的功能块,每个功能块实现自己的内容,之后对页面的管理和维护就变得很容易了. 注册组件的 ...

  5. IdentityServer4源码解析_4_令牌发放接口

    目录 identityserver4源码解析_1_项目结构 identityserver4源码解析_2_元数据接口 identityserver4源码解析_3_认证接口 identityserver4 ...

  6. Java中Comparable和Comparator的区别

    前言 最近复习遇到了这个问题,在此进行一个详细的记录,分享给大家. 两个接口的区别 包区别 Comparable接口是在java.lang下. Comparator接口是在java.util下. 使用 ...

  7. Hive架构原理

    什么是Hive Hive是由Facebook开源用于解决海量结构化日志的数据统计:Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射 成一张表,并提供类SQL查询功能,底层计算引 ...

  8. vim-0-indent(缩进)

    缩进: 参考自http://liuzhijun.iteye.com/blog/1831548,http://blog.csdn.net/chenxiang6891/article/details/41 ...

  9. Ubuntu 安装 tensorflow-gpu 1.4 包含 CUDA 8.0 和cuDNN

    硬件环境:NVIDIA GTX 980 Ti 系统环境:Ubuntu 16.04 64位 一.安装 NVIDIA驱动 关闭 Secure Boot 具体如何禁用 BIOS 中的 Secure Boot ...

  10. 知识图谱与机器学习 | KG入门 -- Part1-b 图深度学习

    介绍 我们正在定义一种新的机器学习方法,专注于一种新的范式 -- Data Fabric. 在上一篇文章中,我们对机器学习给出了新的定义: 机器学习是一种自动发现Data Fabric中隐藏的&quo ...