一、背景

当使用replace语句更新access_apps表时,原有的mark列、remark列的信息丢失。

CREATE TABLE `access_apps` (
  `base` varchar(11) NOT NULL DEFAULT '',
  `business` varchar(64) NOT NULL DEFAULT '',
  `owt` varchar(64) NOT NULL DEFAULT '',
  `pdl` varchar(64) NOT NULL DEFAULT '',
  `app_group_id` varchar(64) NOT NULL DEFAULT '',
  `app_artifact_id` varchar(64) NOT NULL DEFAULT '',
  `app` varchar(128) NOT NULL DEFAULT '',
  `appkey` varchar(128) NOT NULL DEFAULT '',
  `version` varchar(128) NOT NULL DEFAULT '',
  `status` tinyint(1) NOT NULL DEFAULT '0',
  `mark` int(11) NOT NULL DEFAULT '0',
  `remark` varchar(128) NOT NULL DEFAULT '',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`base`,`business`,`owt`,`pdl`,`app_group_id`,`app_artifact_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@Insert("replace into access_apps(base,business,owt,pdl,app_group_id,app_artifact_id,app,appkey,version,status) " +
        "values(#{base},#{business},#{owt},#{pdl},#{app_group_id},#{app_artifact_id},#{app},#{appkey},#{version},#{status})")
void saveAccessRecord(AccessRecord accessRecord);

access_apps表中有mark、remark列,replace语句中没有mark、remark列。

错误原因:

错误认为replace语句相当于当主键冲突时,已修改的列将使用新值,未修改的列将使用旧值

replace语句对于缺失的列将使用默认值,而不是当前行中的值,导致原有的列信息丢失。

二、replace语句详解

MySQL中replace语句具体算法如下:

1. 尝试把新行插入到表中

2. 当因为主键(PRIMARY KEY)冲突错误或(UNIQUE INDEX)唯一索引重复错误而造成插入失败时:

a. 从表中删除含有重复关键字值的冲突行

b. 再次尝试把新行插入到表中

可以看出replace语句相当于insert操作或者delete+insert操作,因此,为了能够使用replace语句,必须同时具备insert和delete的权限。

replace语句执行时,分以下两种情况:

情况1:insert

当不存在主键冲突或唯一索引冲突,相当于insert操作

情况2:delete and insert

当存在主键冲突或唯一索引冲突,相当于delete操作,加insert操作

所有列的值均取自在replace语句中被指定的值,所有缺失的列的值被设置为列的默认值,这和INSERT一样。

不能引用当前行的值,然后用于更新新行。(因为当当前行与新行发生冲突时,当前行将被删除,也就无法被引用了!)

例如,如果使用一个形如“SET col_name = col_name + 1”的赋值,则对位于右侧的列名称的引用会被作为DEFAULT(col_name)处理。

因此,该赋值相当于SET col_name = DEFAULT(col_name) + 1。

replace语句的返回值

replace语句会返回一个数,来指示受影响的行的数目。该数是被删除和被插入的行数的和。

1.如果对于一个replace语句,返回值为1,则一行被插入,同时没有行被删除。

2.如果该数大于1,则在新行被插入前,有一个或多个旧行被删除。如果表包含多个唯一索引,并且新行与不同行的不同的唯一索引发生了重复。

示例1:test表id作为主键

CREATE TABLE test (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  data VARCHAR(64) DEFAULT NULL,
  ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);
mysql> REPLACE INTO test VALUES (1, 'Old''2014-08-20 18:47:00');
Query OK, 1 row affected (0.04 sec)
 
mysql> REPLACE INTO test VALUES (1, 'New''2014-08-20 18:47:42');
Query OK, 2 rows affected (0.04 sec)
 
mysql> SELECT FROM test;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)

第一个replace语句执行时,test表中没有数据,没有发生冲突,所以相当于执行了insert操作,返回值为1(1 row affected)。

第二个replace语句执行时,id=1的数据已存在,发生了主键冲突,所以相当于先执行了delete操作,然后执行了insert操作,返回值为2(2 rows affected)。

示例2:test表id,ts作为主键

CREATE TABLE test2 (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  data VARCHAR(64) DEFAULT NULL,
  ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id, ts)
);
mysql> REPLACE INTO test2 VALUES (1, 'Old''2014-08-20 18:47:00');
Query OK, 1 row affected (0.05 sec)
 
mysql> REPLACE INTO test2 VALUES (1, 'New''2014-08-20 18:47:42');
Query OK, 1 row affected (0.06 sec)
 
mysql> SELECT FROM test2;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | Old  | 2014-08-20 18:47:00 |
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
rows in set (0.00 sec)

因id,ts作为主键,replace时未发生主键冲突,所以均相当于insert操作。

三、参考资料

https://dev.mysql.com/doc/refman/5.7/en/replace.html MySQL官网replace语法

http://www.cnblogs.com/c-961900940/p/6197878.html  MySQL中replace into的用法

http://www.cnblogs.com/martin1009/archive/2012/10/08/2714858.html mysql replace into用法详细说明

MySQL中的replace语句的更多相关文章

  1. mysql中常用的语句整理

    mysql中常用的语句: 1:创建带自增长的主键的表 DROP TABLE IF EXISTS user_login ; CREATE TABLE user_login (   user_id INT ...

  2. Mysql中的条件语句if、case

    Mysql中的条件语句在我们对数据进行转换的时候比较有用,这样就不需要创建中转表. IF 函数 IF(expr1,expr2,expr3) 如果 expr1 是TRUE (expr1 <> ...

  3. MySQL中执行sql语句错误 Error Code: 1093. You can't specify target table 'car' for update in FROM clause

    MySQL中执行sql语句错误 Error Code: 1093. You can't specify target table 'car' for update in FROM clause 201 ...

  4. 浅谈MySQL中优化sql语句查询常用的30种方法 - 转载

    浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使 ...

  5. 重新认识MySQL中的COUNT语句

    在数据库的增删改查操作中,使用最频繁的就是查询操作. 而在所有查询操作中,统计数量操作更是经常被用到. 关于数据库中行数统计,无论是MySQL还是Oracle亦或者是SqlServer,都有一个函数可 ...

  6. MySQL中使用replace into语句批量更新表数据

    作为示例,我们在这里使用名为testdb的数据库,并且在其中创建两张一模一样的表: drop table if exists test_table_1; create table test_table ...

  7. 在MySQL中阻止UPDATE语句没有添加WHERE条件的发生

    如果在生产环境中使用UPDATE语句更新表数据,此时如果忘记携带本应该添加的WHERE条件,那么..Oh,no…后果可能不堪设想.那么有没有什么办法可以阻止这样的事情发生,又不使用任何的审核工具呢.. ...

  8. mysql中,执行delete语句时出现Lock wait timeout exceeded问题

    问题描述: 当我插入一条记录时,在调用save方法的时候出现了异常(记录重复了),导致了后面的commit语句不能执行了.这时我在数据库中删除重复记录时发现该表已经被锁上了.即出现错误.但过了一会再次 ...

  9. 关于mysql中实现replace的sql语句

    update  表名  set  字段名=replace(字段名, '旧字符串', '新字符串')

随机推荐

  1. Factor Pattern----工厂模式

    一. 概念 工厂模式就是负责生成其他对象的类或方法,就是把创建对象的过程封装起来,这样随时可以产生一个新的对象,减少代码之间耦合. 二. 使用场景(原因) 工厂模式可以将对象的生产从直接new 一个对 ...

  2. 一篇迟到的gulp文章

    前言 这篇文章本应该在去年17年写的,但因为种种原因没有写,其实主要是因为懒(捂脸).gulp出来的时间已经很早了,16年的时候还很流行,到17年就被webpack 碾压下去了,不过由于本人接触gul ...

  3. eclipse工程当中的.classpath 和.project文件什么作用?

    .project是项目文件,项目的结构都在其中定义,比如lib的位置,src的位置,classes的位置.classpath的位置定义了你这个项目在编译时所使用的$CLASSPATH .classpa ...

  4. 只需几分钟跟小猫学前端(内含视频教程):nodejs基础之用express、ejs、mongdb建设简单的网站

    开门见山视频教程 https://v.qq.com/x/page/d0645s79xrq.html 前 言: 这是小猫的第二篇node教程,第一篇教程是一个简单的试水,小猫的node教程面向对象为没有 ...

  5. Mybatis 系列6

    上篇系列5中 简单看了一下TypeHandler, 本次将结束对于mybatis的配置文件的学习, 本次涉及到剩下没提及到的几个节点的配置:objectFactory.databaseIdProvid ...

  6. java之Spring实现控制反转

    先来复习一下多态吧,简单点讲,就是一个类的引用可以指向其本身以及其子类的对象. Like these: FatherClass a = new FatherClass(); FatherClass a ...

  7. jQuery的学习笔记2

    jQuery学习笔记 Day two Chapter two 选择器 类选择器 语法结构:$(“.classname”) javascript里面没有类选择器所以这个时候使用jQuery会更加的简便 ...

  8. Scrapy爬虫框架补充内容一(Linux环境)

    Scrapy爬虫框架结构及工作原理详解 scrapy框架的框架结构如下: 组件分析: ENGINE:(核心):处理整个框架的数据流,各个组件在其控制下协同工作 SCHEDULER(调度器):负责接收引 ...

  9. python_特殊函数

    __new__() 类的静态方法,用于确定是否要创建对象__init__() 构造函数,生成对象时调用__del__() 析构函数,释放对象时调用__add__() +__sub__() -__mul ...

  10. Java反射-修改private final成员变量值,你知道多少?

    大家都知道使用java反射可以在运行时动态改变对象的行为,甚至是private final的成员变量,但并不是所有情况下,都可以修改成员变量.今天就举几个小例子说明.  基本数据类型 String类型 ...