美文网首页MySQL 开发
MySQL insert or update

MySQL insert or update

作者: 殷天文 | 来源:发表于2018-12-04 22:53 被阅读160次

    业务场景

    • 我们经常会遇到类似的业务场景,插入一条数据如果他不存在则执行 insert ,当这条记录存在的时候,我们去 update 他的一些属性(或者什么都不做)。

    解决方案:

    • 使用 ON DUPLICATE KEY UPDATE
      主键 或者 唯一约束 重复时,执行更新操作。
    • 使用 REPLACE INTO
      主键 或者 唯一约束 重复时,先 delete 再 insert。

    ON DUPLICATE KEY UPDATE

    • 创建表,建立唯一约束,准备一条数据
    CREATE TABLE `stu_class_ref` (
      `id` varchar(30) NOT NULL,
      `stu_id` varchar(30) DEFAULT NULL,
      `class_id` varchar(30) DEFAULT NULL,
      `note` varchar(100) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `stu_id` (`stu_id`,`class_id`) USING BTREE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    INSERT INTO 
    `test`.`stu_class_ref`(`id`, `stu_id`, `class_id`, `note`) 
    VALUES ('001', 'zhangsan', 'yuwen', NULL);
    
    准备数据
    • 使用 ON DUPLICATE KEY UPDATE
    INSERT INTO 
    `test`.`stu_class_ref`(`id`, `stu_id`, `class_id`, `note`) 
    VALUES (UUID_SHORT(), 'zhangsan', 'yuwen', '我喜欢语文:)')
    ON DUPLICATE KEY UPDATE note = '我喜欢语文:)'
    > Affected rows: 2
    > 时间: 0.042s
    
    • Affected rows: 2,MySQL 检查插入的行是否会产生重复键错误,如果会则执行update
    ON DUPLICATE KEY UPDATE
    • 如果想要引用 VALUES 中的值,参考如下
    INSERT INTO 
    `test`.`stu_class_ref`(`id`, `stu_id`, `class_id`, `note`) 
    VALUES (UUID_SHORT(), 'zhangsan', 'yuwen', NULL)
    ON DUPLICATE KEY UPDATE note = VALUES(class_id)
    > Affected rows: 2
    > 时间: 0.006s
    
    ON DUPLICATE KEY UPDATE

    REPLACE INTO

    • MySQL 中 还有一个黑科技语法 REPLACE INTO
    REPLACE INTO `stu_class_ref`(`id`, `stu_id`, `class_id`, `note`) 
    VALUES (UUID_SHORT(), 'zhangsan', 'yuwen', NULL)
    > Affected rows: 2
    > 时间: 0.004s
    
    REPLACE INTO
    • REPLACE INTO 就比较简单粗暴了,他会先执行delete 操作,然后insert

    ON DUPLICATE KEY UPDATE 与 REPLACE INTO

    • 再来创建一张表, 创建三个唯一约束, 插入三条数据
    CREATE TABLE `interesting` (
      `id` varchar(30) NOT NULL,
      `uni_a` varchar(30) DEFAULT NULL,
      `uni_b` varchar(30) DEFAULT NULL,
      `uni_c` varchar(30) DEFAULT NULL,
      `version` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `uni_a` (`uni_a`) USING BTREE,
      UNIQUE KEY `uni_b` (`uni_b`) USING BTREE,
      UNIQUE KEY `uni_c` (`uni_c`) USING BTREE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    INSERT INTO `test`.`interesting`(`id`, `uni_a`, `uni_b`, `uni_c`, `version`) 
    VALUES ('1', 'a', 'a', 'a', NULL);
    INSERT INTO `test`.`interesting`(`id`, `uni_a`, `uni_b`, `uni_c`, `version`) 
    VALUES ('2', 'b', 'b', 'b', NULL);
    INSERT INTO `test`.`interesting`(`id`, `uni_a`, `uni_b`, `uni_c`, `version`) 
    VALUES ('3', 'c', 'c', 'c', NULL);
    
    准备数据
    1. 执行 ON DUPLICATE KEY UPDATE
    INSERT INTO `interesting`(`id`, `uni_a`, `uni_b`, `uni_c`, `version`) 
    VALUES (UUID_SHORT(), 'a', 'b', 'c', NULL)
    ON DUPLICATE KEY UPDATE version = 666
    > Affected rows: 2
    > 时间: 0.049s
    
    ON DUPLICATE KEY UPDATE
    • Affected rows: 2 但是其实三条主键都有冲突了
    1. 再看一下 REPLACE INTO
    REPLACE INTO `interesting`(`id`, `uni_a`, `uni_b`, `uni_c`, `version`) 
    VALUES (UUID_SHORT(), 'a', 'b', 'c', NULL)
    > Affected rows: 4
    > 时间: 0.026s
    
    REPLACE INTO
    • Affected rows: 4 REPLACE INTO 将三条有冲突的全部delete 然后 insert

    总结:

    • ON DUPLICATE KEY UPDATE 只会对所匹配的第一行进行update,
    • REPLACE INTO 会对所有匹配行进行delete, insert
    • 所以应避免对有多个唯一索引的表使用

    相关文章

      网友评论

        本文标题:MySQL insert or update

        本文链接:https://www.haomeiwen.com/subject/ctkvcqtx.html