语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name
    [PARTITION (partition_name,...)] 
    [(col_name,...)]
    {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
Or:
REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name
    [PARTITION (partition_name,...)] 
    SET col_name={expr | DEFAULT}, ...
Or:
REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name
    [PARTITION (partition_name,...)]  
    [(col_name,...)]
    SELECT ...

原理

replace的工作机制有点像insert,只不过如果在表里如果一行有PRIMARY KEY或者UNIQUE索引,那么就会把老行删除然后插入新行。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@test 03:23:55>show create table lingluo\G
*************************** 1. row ***************************
       Table: lingluo
Create TableCREATE TABLE `lingluo` (
  `a` int(11) NOT NULL DEFAULT '0',
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`a`),--------------------------同时存在PK约束
  UNIQUE KEY `uk_bc` (`b`,`c`)----------------唯一索引约束
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.01 sec)
 
root@test 02:01:44>select from lingluo;
Empty set (0.00 sec)
 
root@test 03:27:40>replace into lingluo values(1,10000,3,4);--------表里没有已存在的记录相当于insert
Query OK, 1 row affected (0.00 sec)-----------------------affect_rows是1
binlog格式:

1
2
3
root@test 02:11:18>replace into lingluo values(1,10000,3,5);-------已经存在记录,且PK和UK同时冲突的时候,相当于先delete再insert
Query OK, 2 rows affected (0.00 sec)----------------------affect_rows是2,是delete和insert行数的总和
binlog格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@test 02:26:09>select from lingluo;
+---+-------+------+------+
| a | b     | c    | d    |
+---+-------+------+------+
| 1 | 10000 |    3 |    5 |
+---+-------+------+------+
1 row in set (0.00 sec)
 
root@test 02:31:54>replace into lingluo values(1,10000,4,5);-------已经存在记录,且PK同时冲突的时候,相当于先delete再insert
Query OK, 2 rows affected (0.00 sec)---------------------------------affect_rows是2,是delete和insert行数的总和
 
root@test 02:32:02>select from lingluo;
+---+-------+------+------+
| a | b     | c    | d    |
+---+-------+------+------+
| 1 | 10000 |    4 |    5 |
+---+-------+------+------+
binlog格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@test 02:37:04>replace into lingluo values(4,10000,6,5);
Query OK, 1 row affected (0.00 sec)
root@test 02:37:59>replace into lingluo values(6,10000,6,5);-------已经存在记录,且UK同时冲突的时候,直接update
Query OK, 2 rows affected (0.00 sec)---------------------------------affect_rows是2
 
root@test 02:40:31>select from lingluo;
+---+-------+------+------+
| a | b     | c    | d    |
+---+-------+------+------+
| 1 | 10000 |    4 |    5 |
| 3 | 10000 |    5 |    5 |
| 6 | 10000 |    6 |    5 |
+---+-------+------+------+
rows in set (0.00 sec)
binlog格式:

疑问:

既然uk冲突的时候是update,那么为什么affect_rows都是2呢?让我们从源码上分析看下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
指定列replace:
root@test 03:34:37>select from u;
+----+------+------+
| id | age  | d    |
+----+------+------+
|  0 |    1 |  126 |
|  1 |    0 |    1 |
|  3 |    1 |  123 |
|  4 |    1 |  127 |
|  5 |    0 |   12 |
|  7 |    2 |  129 |
+----+------+------+
rows in set (0.00 sec)
 
root@test 03:34:37>select from u;
+----+------+------+
| id | age  | d    |
+----+------+------+
|  0 |    1 |  126 |
|  1 |    0 |    1 |
|  3 |    1 |  123 |
|  4 |    1 |  127 |
|  5 |    0 |   12 |
|  7 |    2 |  129 |
+----+------+------+
rows in set (0.00 sec)
 
root@test 03:34:40>replace into u (age,d)values(0,130);
Query OK, 2 rows affected, 1 warning (0.01 sec)
 
root@test 03:40:39>show warnings;
+---------+------+-----------------------------------------+
Level   | Code | Message                                 |
+---------+------+-----------------------------------------+
| Warning | 1364 | Field 'id' doesn't have a default value |
+---------+------+-----------------------------------------+
1 row in set (0.00 sec)
 
root@test 03:40:47>select from u;
+----+------+------+
| id | age  | d    |
+----+------+------+
|  0 |    0 |  130 |-----------------因为id是parimary但是没有auto_creasement,由126变成130
|  1 |    0 |    1 |
|  3 |    1 |  123 |
|  4 |    1 |  127 |
|  5 |    0 |   12 |
|  7 |    2 |  129 |
+----+------+------+
rows in set (0.00 sec)

用的时候需要注意的是:

  1. 如果指定replace列的话,尽量写全,要不然没有输入值的列数据会被赋成默认值(因为是先delete在insert),就和普通的insert是一样的,所以如果你要执行replace语句的话是需要insert和delete权限的。

    如果你需要执行 SET col_name = col_name + 1,就相当于执行col_name = DEFAULT(col_name) + 1.

  2. replace语句如果不深入看的话,就和insert一样,执行完后没什么反应

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
root@test 04:20:04>select from u;
+----+------+------+
| id | age  | d    |
+----+------+------+
|  0 |    0 |  130 |
|  1 |    0 |    1 |
|  3 |    1 |  123 |
|  4 |    1 |  127 |
|  5 |    0 |   12 |
|  7 |    2 |  129 |
+----+------+------+
rows in set (0.00 sec)
 
root@test 04:20:10>replace into u (id,d) values(8,232);
Query OK, 1 row affected (0.01 sec)
 
root@test 04:20:39>select from u;
+----+------+------+
| id | age  | d    |
+----+------+------+
|  0 |    0 |  130 |
|  1 |    0 |    1 |
|  3 |    1 |  123 |
|  4 |    1 |  127 |
|  5 |    0 |   12 |
|  7 |    2 |  129 |
|  8 | NULL |  232 |
+----+------+------+
rows in set (0.00 sec)
 
root@test 04:20:43>replace into u (id,d) values(7,232);
Query OK, 3 rows affected (0.01 sec)----------注意这里affect_rows是3,因为主键7已经存在,唯一索引232已经存在,所以需要删除id为7和8的行,然后插入新行
 
root@test 04:20:52>select from u;
+----+------+------+
| id | age  | d    |
+----+------+------+
|  0 |    0 |  130 |
|  1 |    0 |    1 |
|  3 |    1 |  123 |
|  4 |    1 |  127 |
|  5 |    0 |   12 |
|  7 | NULL |  232 |
+----+------+------+
rows in set (0.00 sec)
 
root@test 04:20:55>

MySQL给replace和load data....replace用的算法是:

  1. 尝试向表里插入新行

  2. 当表里唯一索引或者primary key冲突的时候:

    a. delete冲突行

    b.往表里再次插入新行

如果遇到重复行冲突,存储过程很可能当作update执行,而不是delete+insert,但是显式上都是一样的。这里没有用户可见的影响除了存储引擎层Handler_xxx的状态变量。

因为REPLACE ... SELECT语句的结果依赖于select的行的顺序,但是顺序没办法保证都是一样的,有可能从master和slave的都不一样。正是基于这个原因,MySQL 5.6.4以后,REPLACE ... SELECT语句被标记为基于statement的复制模式不安全的。基于这个变化,当使用STATEMENT记录二进制日志的时候,如果有这样的语句就会在log里面输出一个告警,同样当使用MIXED行复制模式也会记录告警。

在MySQL5.6.6之前的版本,replace影响分区表就像MyISAM使用表级锁锁住所有的分区表一样。当使用 REPLACE ... PARTITION语句时确实会发生上述情况。(使用基于行锁的InnoDB引起不会发生这种情况。)在MySQL 5.6.6以后的版本MySQL使用分区锁,只有当分区(只要没有分区表的列更新)包含了REPLACE语句并且WHERE实际匹配到的才会锁住那个分区;否则的话就会锁住整个表。

操作形式:

binlog格式:

结论

  1. 当存在pk冲突的时候是先delete再insert

  2. 当存在uk冲突的时候是直接update

mysql replace语句的更多相关文章

  1. Mysql Replace语句的使用

    Mysql Replace语句的语法: REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name,...)] VALUES ({expr ...

  2. 慎用MySQL replace语句

    语法: REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [PARTITION (partition_name,...)] [(col_name,... ...

  3. MySQL数据库INSERT、UPDATE、DELETE以及REPLACE语句的用法详解

    本篇文章是对MySQL数据库INSERT.UPDATE.DELETE以及REPLACE语句的用法进行了详细的分析介绍,需要的朋友参考下   MySQL数据库insert和update语句引:用于操作数 ...

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

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

  5. MySQL中的replace语句

    一.背景 当使用replace语句更新access_apps表时,原有的mark列.remark列的信息丢失. CREATE TABLE `access_apps` (   `base` varcha ...

  6. 转载:MySQL数据库INSERT、UPDATE、DELETE以及REPLACE语句的用法详解

    转自:http://www.jb51.net/article/39199.htm 本篇文章是对MySQL数据库INSERT.UPDATE.DELETE以及REPLACE语句的用法进行了详细的分析介绍, ...

  7. MySQL 当记录不存在时insert,当记录存在时update(ON DUPLICATE KEY UPDATE, REPLACE语句)

    MySQL 当记录不存在时insert,当记录存在时更新 网上基本有三种解决方法. 第一种:示例一:insert多条记录 假设有一个主键为 client_id 的 clients 表,可以使用下面的语 ...

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

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

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

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

随机推荐

  1. .Net Core 跨平台应用使用串口、串口通信 ,可能出现的问题、更简洁的实现方法

    前些天在学习在 .NET Core下,跨平台使用串口通讯,有一篇文章说到在Linux/物联网下,实现通讯. 主要问题出现在以下两个类库 SerialPortStream flyfire.CustomS ...

  2. SharePoint列表数据清除

    --获取站点对象 $spWeb =get-spweb http://123.sinochem.com --获取具体列表对象 $spList =$spWeb.GetListFromUrl("h ...

  3. sql盲注之报错注入(附自动化脚本)

    作者:__LSA__ 0x00 概述 渗透的时候总会首先测试注入,sql注入可以说是web漏洞界的Boss了,稳居owasp第一位,普通的直接回显数据的注入现在几乎绝迹了,绝大多数都是盲注了,此文是盲 ...

  4. cmd下查看应用端口情况

    在win10开始窗口右侧的空白处点击CMD,在上方弹出窗口中选择命令提示符,双击进入 在弹出命令界面中,输入netstat -na命令后回车,如下图所示,可以看到所有目前打开的端口 如果要查看打开端口 ...

  5. eclipse上搭建Spring环境

    搭建环境之前要下载Spring Tool Suite和Spring framework 1.Spring IDE 下载(也叫Spring Tool Suite 简称 STS),进官网,直接给链接htt ...

  6. 使用ie的filter来解决rgba在IE8下没有效果的问题

    使用ie的filter来解决rgba在IE8下没有效果的问题,css代码如下: background: rgba(255,255,255,0.1); filter:progid:DXImageTran ...

  7. mysql 执行 sql 语句提示Parameter '@XXX' must be defined

    执行 sql 语句 MySqlException: Parameter '@maxNo' must be defined. 执行 sql 中含有自定义变量 @maxNo,抛出异常 解决方法: 连接字符 ...

  8. 剑指offer三十三之丑数

    一.题目 如果一个数的因子中,出去1和本身以外,质数因子只包含2.3和5,则把改数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含质数因子7. 习惯上我们把1当做是第一个 ...

  9. (转) Rabbitmq学习笔记

    详见原文: http://blog.csdn.net/shatty/article/details/9529463 Rabbitmq学习笔记

  10. Netty核心概念(6)之Handler

    1.前言 本节介绍Netty中第三个重要的概念——Handler,这个在前两节都提到了,尤其是Channel和Handler联系紧密.handler本身的设计非常简单,但是所起到的作用却很大,Nett ...