数据库技巧: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使用的问题,具体点击这里

五、总结

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

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

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

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

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

感谢您的支持和理解!

相关推荐
码出极致几秒前
Redisson分布式缓存与数据一致性保障
后端
用户790349033713 分钟前
springboot集成redisson实现redis分布式锁
后端
陈随易8 分钟前
程序员的新玩具,MoonBit(月兔)编程语言科普
前端·后端·程序员
老纪的技术唠嗑局13 分钟前
单机分布式一体化数据库的架构设计与优化
数据库·分布式
码出极致14 分钟前
Redisson秒杀系统中的分布式锁应用
后端
GBASE19 分钟前
“G”术时刻:Linux环境下通过ESQL/C方式连接南大通用GBase 8s数据库(上)
数据库
一只fish20 分钟前
MySQL 8.0 OCP 1Z0-908 题目解析(23)
数据库·mysql
不拘小节曹阿蛮21 分钟前
Ubuntu 20.04 ARM64架构下面安装mysql5.7.22
数据库
xiaok21 分钟前
@Param注解的作用
java·后端
Sperains29 分钟前
async/await和Synchronous的区别
后端