MySQL原生语句保存或更新的编写方法综述

背景

在正常的开发中,我们经常遇到更新数据的场景:首先判断数据是否存在于库表中,有更新,并且没有插入。

如果使用的是Hibernate,可以很方便的使用saverorupdate方法,但如何使用SQL语句

初学者最常用的方法是先查询记录是否存在SELECT语句,然后使用UPDATE语句更新,不存在插入INSERT语句。

但这显然不够优雅,还有几个问题:

为了执行更新操作,程序中使用了两个SQL查询,当系统负载比较大时,性能仍会受到影响。

代码中有一个if语句,它清楚地做了一件事,但是代码很长。代码农民都是懒惰的人,为什么他们只做简单的事情:)。



所以问题是,你如何使用SQL语句来实现saverorupdate优雅

最近的工作也遇到了类似的问题,数据的更新,写的也开始感到恼火。记得有一个合并在甲骨文写作的方法,和一个类似的实现基于如下眉目传情:



数据不存在和插入,没有操作

忽略插入INSERT语句实现数据不存在关键词的使用,并没有运行。实现的逻辑是,INSERT语句或唯一键冲突发生主键冲突时,误差不扔,和插入语句直接忽略。到官方网站的相关介绍如下:



如果使用忽略关键字,则在执行INSERT语句时发生的错误将被忽略。例如,如果不忽略,复制表中现有的唯一索引或主键值的行会导致重复的关键错误,语句被终止。如果忽略,该行将被丢弃,不会发生错误。忽略的错误可能会产生警告,而不是重复的键,错误不会。



MySQL官方文档提供标准语法:

复制代码代码如下所示:

将忽略

为tbl_name

{分区(partition_name,…)}

{ }(col_name,…)

{价值}({ expr | |默认},…),(…),…



也许

复制代码代码如下所示:

将忽略

{在} tbl_name

{分区(partition_name,…)}

{ }(col_name,…)

选择…



除了一个以上的忽略关键字外,与一般INSERT语句没有区别。



栗子:

1。构建测试表

复制代码代码如下所示:

创建表(` test_tab `

`名字` varchar(64)不为空,

年龄int(11)不为空,

主键(名称)

InnoDB引擎=默认的字符集utf8);



2。插入一段数据

复制代码代码如下所示:

插入` test_tab `(`名字`,`年龄`)值('zhangsan ',24)



为test_tab表的当前数据:

复制代码代码如下所示:

名称|年龄

- |:—:—

24 | zhangsan



三.一步2插入语句的执行将报告异常:

复制代码代码如下所示:

{错误} 1062重复entry'zhangsan'for key'primary



4。将忽略关键字添加到步骤2的INSERT语句中,不报告异常,并且不更新现有的数据。

复制代码代码如下所示:

将忽略为` test_tab `(`名字`,`年龄`)值('zhangsan ',24);





语句执行:

受影响的线:0

时间:0.000s



为test_tab表的当前数据:

复制代码代码如下所示:

名称|年龄

- |:—:—

24 | zhangsan



没有存在是插入,存在是被更新的,一个(使用重复关键字更新关键字)

使用INSERT语句中的重复关键字更新关键字,插入数据,并更新现有操作。判断数据重复的逻辑仍然是主键冲突或唯一密钥冲突。

官方网站的相关介绍如下:



如果指定了重复密钥更新,并且插入了一个行,该行将导致唯一索引或主键中的重复值,则执行旧行的更新。每行的受影响行值是插入行1,如果现有行为新行,则更新为0,如果现有行设置为当前值,则行为2。



MySQL官方文档提供标准语法:

复制代码代码如下所示:

插入

{在} tbl_name

{分区(partition_name,…)}

{ }(col_name,…)

{价值}({ expr | |默认},…),(…),…

{重复密钥更新

col_name =表达式

{,col_name =表达式}…}



或:

复制代码代码如下所示:

插入

{在} tbl_name

{分区(partition_name,…)}

设置默认col_name = { } | expr,…

{重复密钥更新

col_name =表达式

{,col_name =表达式}…}



或:

复制代码代码如下所示:

插入

{在} tbl_name

{分区(partition_name,…)}

{ }(col_name,…)

选择…

{重复密钥更新

col_name =表达式

{,col_name =表达式}…}



可见,或原始插入语句的原始书写。



栗子:

1。利用新建的test_tab表,此表中的数据如下:

复制代码代码如下所示:

名称|年龄

- |:—:—

24 | zhangsan



2。使用同一主键的同一INSERT语句,仍然存在重复的密钥错误

复制代码代码如下所示:

插入` test_tab `(`名字`,`年龄`)值('zhangsan ',50);



{错误} 1062重复entry'zhangsan'for key'primary



三.加上重复的密钥更新的INSERT语句现在。关键词 uff1a

复制代码代码如下所示:

插入` test_tab `(`名字`,`年龄`)值('zhangsan ',50)

关于重复密钥更新'年龄= 50;





受影响的线:2

时间:0.025s



4。在这个时候is'zhangsan主键的数据,年龄字段已更新:

复制代码代码如下所示:

名称|年龄

- |:—:—

50 | zhangsan



5、当然,如果主键不冲突,效果与通常的INSERT语句相同:

复制代码代码如下所示:

插入` test_tab `(`名字`,`年龄`)值('lisi ',30)

关于重复密钥更新'年龄= 30;





受影响的线:1

时间:0.009s

复制代码代码如下所示:

名称|年龄

- |:—:—

50 | zhangsan

Lisi | 30



插入不存在的,存在的更新,和第二(使用REPLACE语句实现)

保存或更新在MySQL中有另一个实现,替换成语句,它与Oracle的合并有点类似。判断数据重复的逻辑仍然是主键或唯一键冲突:

复制代码代码如下所示:

{ } |取代low_priority延迟

{在} tbl_name

{分区(partition_name,…)}

{ }(col_name,…)

{价值}({ expr | |默认},…),(…),…



或:

复制代码代码如下所示:

{ } |取代low_priority延迟

{在} tbl_name

{分区(partition_name,…)}

设置默认col_name = { } | expr,…



或:

复制代码代码如下所示:

{ } |取代low_priority延迟

{在} tbl_name

{分区(partition_name,…)}

{ }(col_name,…)

选择…





栗子:

1。上述test_tab表数据仍被使用,此时的数据如下

复制代码代码如下所示:

名称|年龄

- |:—:—

50 | zhangsan

Lisi | 30



2。一般使用INSERT语句插入名称= zhangsan的数据和报告的主键冲突。但改变替换成…的说法是没有问题的:

复制代码代码如下所示:

替换成` test_tab `(`名字`,`年龄`)值('zhangsan ',30);





受影响的线:2

时间:0.009s

三.以下结果如下:

复制代码代码如下所示:

名称|年龄

- |:—:—

30 | zhangsan

Lisi | 30



对于操作的结果,它是非常喜欢保存或更新,但实施不同于重复密钥更新关键字插入。当替换语句,重复数据删除,然后将新数据插入,更新不更新,但删除> insert.in大多数情况下,这不是一个用替换来完成更新操作的问题,但有一个场景,必须特别注意:

当更新表的插入、更新和删除触发器的替换语句使用时必须特别小心。因为根据业务逻辑,数据更新后,应触发更新触发,但使用替换语句,将触发删除和插入触发器更新如果有一些特殊的操作触发(如记录操作日志)的话,使用替代会导致业务逻辑的混乱。

因此,当更新表有触发器场景时,使用插入的重复关键字更新关键字是更合适的。

以上是本文中描述的所有内容,我希望能让您更好地理解MySQL中的保存和更新语句。