数据库技巧:ON DUPLICATE KEY UPDATE的灵活处理

引用

在数据库数据插入遇到重复键冲突的时候,有的时候需要忽略继续插入,但是有的时候则需要更新。

在上一篇文章我介绍了怎么忽略继续插入数据库技巧:INSERT IGNORE的高效插入策略

这篇文章我将介绍一下怎么在数据库层面执行更新操作。

一、认识 ON DUPLICATE KEY UPDATE 语句

ON DUPLICATE KEY UPDATE 是 MySQL 提供的一个非常强大的功能,用于在插入数据时处理重复键冲突。它允许你在插入数据时指定,如果发生重复键冲突(如主键或唯一索引冲突),则执行更新操作,而不是报错。这种方式非常适合在需要"插入或更新"逻辑的场景中使用。

特点插入或更新

MySQL官方介绍

二、基本语法

ON DUPLICATE KEY UPDATE 的语法结构如下:

sql 复制代码
INSERT INTO table_name (column1, column2, ..., columnN)
VALUES (value1, value2, ..., valueN)
ON DUPLICATE KEY UPDATE
    column1 = value1,
    column2 = value2,
    ...,
    columnN = valueN;
  • INSERT INTO table_name:指定要插入数据的表。

  • VALUES:指定要插入的值。

  • ON DUPLICATE KEY UPDATE:如果在插入过程中发现唯一键冲突,则执行更新操作。

  • column1 = value1, column2 = value2, ... :指定在发生冲突时需要更新的字段及其新值。

三、工作原理

当执行 INSERT 语句时,如果插入的数据违反了表的唯一性约束(如主键或唯一索引),MySQL 会触发 ON DUPLICATE KEY UPDATE 子句中的更新操作,而不是报错。以下是其工作原理的详细说明:

3.1 插入数据

如果插入的数据没有违反唯一性约束,数据将正常插入。

3.2 更新数据

如果插入的数据违反了唯一性约束(如主键或唯一索引冲突),MySQL 会执行 ON DUPLICATE KEY UPDATE 子句中的更新操作。你可以指定需要更新的字段及其值。

3.3 返回值

ON DUPLICATE KEY UPDATE 的返回值是一个整数,表示操作的结果:

  • 返回值为 1:表示插入成功。

  • 返回值为 2:表示触发了更新操作。

  • 返回值为 n :表示成功插入了 n 行数据(在插入多行时)。

3.4 在MyBatis里面使用的案例

  • login_log_temp 表中按 loginDay 分组聚合后的数据插入到 extension_users 表中
sql 复制代码
<update id="insertOrUpdateUsers">
    insert into extension_users(loginDate, num)
    select loginDay,sum(loginCount) as num
      from login_log_temp
      group by loginDay
    on duplicate key update num = num + values(num)
</update>
  • 根据参数批量插入或者更新到phy_account_site_nick表里面
sql 复制代码
<insert id="insertPhyAccountSiteNick" parameterType="java.util.List">
    insert into phy_account_site_nick
    (
    account_uuid,
    site,
    nick,
    last_show_id,
    last_physical_start_date
    )
    values
    <foreach collection="list" item="item" separator=",">
        (
        #{item.accountId},
        #{item.site},
        #{item.nick},
        #{item.showId},
        #{item.physicalStartDate}
        )
    </foreach>
    ON DUPLICATE KEY UPDATE
    last_show_id = values(last_show_id),
    last_physical_start_date = values(last_physical_start_date)
</insert>

四、避坑(实际开发中,我们要尽量避免使用它)

虽然上面看着用起来非常爽,但是实际我们再实际开发过程中,会尽量避免使用ON DUPLICATE KEY UPDATE子句,特别是在大量或者频繁遇到DUPLICATE KEY的时候,程序会表现出严重的性能滑落。

下面是官网文档的介绍,也是让我们避免使用(注意:这个避免使用是有前提的)。

另外:在MySQL的官方bug列表中,也是有关于ON DUPLICATE KEY UPDATE使用的问题,具体点击这里

五、总结

写这篇文章我是看到有一些人老喜欢使用这个,但是实际随着业务的增长,后续会非常容易踩坑。

个人建议,还是慎用,尽量不用。

特别强调:在大量或频繁遇到重复键冲突时,会导致性能下降。

希望本文对您有所帮助。如果有任何错误或建议,请随时指正和提出。

同时,如果您觉得这篇文章有价值,请考虑点赞和收藏。这将激励我进一步改进和创作更多有用的内容。

感谢您的支持和理解!

相关推荐
康不坦丁1 分钟前
MySQL 的 order by 简化(使用列序号和列别名排序)
后端·mysql
IndulgeCui7 分钟前
【金仓数据库产品体验官】KingbaseES-性能优化深度体验
数据库·性能优化
wadesir15 分钟前
深入理解Rust静态生命周期(从零开始掌握‘static的奥秘)
开发语言·后端·rust
+VX:Fegn089519 分钟前
计算机毕业设计|基于springboot + vue零食商城管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
哈哈哈笑什么27 分钟前
蜜雪冰城1分钱奶茶秒杀活动下,使用分片锁替代分布式锁去做秒杀系统
redis·分布式·后端
雨中飘荡的记忆32 分钟前
Redis_实战指南
数据库·redis·缓存
WZTTMoon43 分钟前
Spring Boot 4.0 迁移核心注意点总结
java·spring boot·后端
寻kiki43 分钟前
scala 函数类?
后端
('-')1 小时前
《从根上理解MySQL是怎样运行的》第二十五章笔记
数据库·笔记·mysql
尽兴-1 小时前
问题记录:数据库字段 `CHAR(n)` 导致前端返回值带空格的排查与修复
前端·数据库·mysql·oracle·达梦·varchar·char