MySql -- 不存在则插入,存在则更新或忽略

本文详细介绍了如何在MySQL中处理插入数据时遇到重复的情况,包括使用INSERT IGNORE、ON DUPLICATE KEY UPDATE和REPLACE INTO语句。这三个方法分别在遇到冲突时忽略新数据、更新已有数据或删除旧数据并插入新数据。通过示例代码展示了在MyBatis中如何实现这些操作。
部署运行你感兴趣的模型镜像

1.前言

Mysql在插入数据时,需要忽略或替换掉重复的数据(依据某个字段,比如Primary Key或

Unique Key来确定是否重复),这时候我们既可以在应用层处理,也可以使用复杂的 SQL 语句来处理(如果仅仅知道一些简单的 SQL 语法的话),当然也可以使用一些简单的 SQL 语法,不过它并不是通用所有的数据库类型。

下面我们以MySQL为例,研究一下insert 怎样去忽略或替换重复数据

2.表实例

表名称:person

表字段:

Column NamePrimary KeyAuto IncrementUnique
idtruetrue
nametrue
age

初始表数据:

idnameage
111Bruce36

3.三个简单例子:

Note:本文的3个例子都需要被插入的表中存在UNIQUE索引PRIMARY KEY字段

1. 不存在则插入,存在则更新

1.1 on duplicate key update

如果插入的数据会导致UNIQUE 索引PRIMARY KEY发生冲突/重复,则执行UPDATE语句,例:

INSERT INTO `person`(`name`, `age`) VALUES('Bruce', 18)
  ON DUPLICATE KEY 
  UPDATE `age`=19; -- If will happen conflict, the update statement is executed

-- 2 row(s) affected

这里受影响的行数是2,因为数据库中存在name='Bruce'的数据,如果不存在此条数据,则受影响的行数为1。

最新的表数据如下:

idnameage
1Bruce18

1.2 replace into

如果插入的数据会导致UNIQUE 索引PRIMARY KEY发生冲突/重复,则先删除旧数据再插入最新的数据,例:

REPLACE INTO `person`(`name`, `age`) VALUES('Bruce', 20);

-- 2 row(s) affected

这里受影响的行数是2,因为数据库中存在name='Jack'的数据,并且id的值会变成2,因为它是先删除旧数据,然后再插入数据,最新的表数据如下:

idnameage
2Bruce20

2. 避免重复插入(存在则忽略)

关键字/句:insert ignore into,如果插入的数据会导致UNIQUE索引PRIMARY KEY发生冲突/重复,则忽略此次操作/不插入数据,例:

INSERT IGNORE INTO `person`(`name`, `age`) VALUES('Bruce', 18);

-- 0 row(s) affected

这里已经存在name='Bruce'的数据,所以会忽略掉新插入的数据,受影响行数为0,表数据不变。

4.三个复杂例子:

我们可以用customerMobile字段作为唯一索引(UNIQUE 索引)

 Mapper类:

package com.example.springbootmybatisplusbruce.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springbootmybatisplusbruce.model.E**Customer;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface E**CustomerMapper extends BaseMapper<E**Customer> {

    /**
     *  不存在则插入,存在则更新
     * on duplicate key update: 如果插入的数据会导致UNIQUE 索引或PRIMARY KEY发生冲突/重复,则执行UPDATE语句
     * @param e**Customer
     * @return
     */
    public int insertDuplicateKeyUpdate(E**Customer e**Customer);

    /**
     * replace into: 如果插入的数据会导致UNIQUE索引 或 PRIMARY KEY 发生冲突/重复,则先删除旧数据,再插入最新的数据
     * @param etcCustomer
     * @return
     */
    public int insertReplaceInto(E**Customer e**Customer);

    /**
     * 避免重复插入
     * insert ignore into: 如果插入的数据会导致UNIQUE索引或PRIMARY KEY发生冲突/重复,则忽略此次操作/不插入数据
     * @param e**Customer
     * @return
     */
    public int insertIgnore(E**Customer e**Customer);
}

xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.springbootmybatisplusbruce.mapper.E**CustomerMapper">

    <resultMap type="com.example.springbootmybatisplusbruce.model.E**Customer" id="E**CustomerResult">
        <result property="id"    column="id"    />
        <result property="customerType"    column="customer_type"    />
        <result property="customerName"    column="customer_name"    />
        <result property="customerMobile"    column="customer_mobile"    />
        .......................................................................
    </resultMap>

    <sql id="selectE**CustomerVo">
        select id, customer_type, customer_name, customer_mobile,
...........................................................................
from etc_customer
    </sql>
    <!-- 不存在则插入,存在则更新 -->
    <!-- on duplicate key update: 如果插入的数据会导致UNIQUE 索引或PRIMARY KEY发生冲突/重复,则执行UPDATE语句 -->
    <insert id="insertDuplicateKeyUpdate" parameterType="com.example.springbootmybatisplusbruce.model.E**Customer">
        INSERT INTO e**_customer(id, customer_type, customer_name, customer_mobile, credential_type, credential_no, status, del_flag, create_by, create_time, update_by, update_time, remark)
            VALUES(#{id}, #{customerType}, #{customerName}, #{customerMobile}, #{credentialType}, #{credentialNo}, #{status}, #{delFlag}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{remark})
            ON DUPLICATE KEY
            UPDATE
            <if test="customerType != null">customer_type=#{customerType},</if>
            <if test="customerName != null  and customerName != ''">customer_name=#{customerName},</if>
            <if test="customerMobile != null  and customerMobile != ''">customer_mobile=#{customerMobile},</if>
            <if test="credentialType != null">credential_type=#{credentialType},</if>
            <if test="credentialNo != null  and credentialNo != ''">credential_no=#{credentialNo},</if>
            <if test="status != null">status=#{status}</if>
    </insert>

    <!-- replace into: 如果插入的数据会导致UNIQUE索引 或 PRIMARY KEY 发生冲突/重复,则先删除旧数据再插入最新的数据 -->
    <insert id="insertReplaceInto">
        REPLACE INTO e**_customer(id, customer_type, customer_name, customer_mobile, credential_type, credential_no, status, del_flag, create_by, create_time, update_by, update_time, remark)
        VALUES(#{id}, #{customerType}, #{customerName}, #{customerMobile}, #{credentialType}, #{credentialNo}, #{status}, #{delFlag}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{remark})
    </insert>

    <!-- 避免重复插入 -->
    <!-- insert ignore into: 如果插入的数据会导致UNIQUE索引或PRIMARY KEY发生冲突/重复,则忽略此次操作/不插入数据 -->
    <insert id="insertIgnore">
        INSERT IGNORE INTO e**_customer(id, customer_type, customer_name, customer_mobile, credential_type, credential_no, status, del_flag, create_by, create_time, update_by, update_time, remark)
        VALUES(#{id}, #{customerType}, #{customerName}, #{customerMobile}, #{credentialType}, #{credentialNo}, #{status}, #{delFlag}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{remark})
    </insert>
</mapper>

 service类:

package com.example.springbootmybatisplusbruce.service;

import com.example.springbootmybatisplusbruce.mapper.ETCCustomerMapper;
import com.example.springbootmybatisplusbruce.model.EtcCustomer;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

@Service
public class FTPFileParseService {

    @Autowired
    private E**CustomerMapper e**CustomerMapper;

    /**
     * 参考文章:https://blog.csdn.net/t894690230/article/details/77996355
     *         https://blog.csdn.net/weixin_45607513/article/details/117470118
     * @throws IOException
     */
    @Transactional(rollbackFor = Exception.class)
    public void fileParse() throws IOException {
        StringBuilder result = new StringBuilder();
        String path = "F:\\Digital marketing\\E** system\\txt-from-ftp\\20210302_VEHICLE.txt";

        long start = System.currentTimeMillis(); //程序执行前的时间戳
        BufferedReader br = new BufferedReader(new FileReader(path));//构造一个BufferedReader类来读取文件
        String line = null;
        while((line = br.readLine())!=null){//使用readLine方法,一次读一行
//            result.append(System.lineSeparator()+s);
            System.out.println("Debug:" + line);
            String [] infoArray = line.split("@~@");
            EtcCustomer e**Customer = new EtcCustomer();
            if(infoArray[0].isEmpty()){continue;}
            e**Customer.setId(Long.valueOf(infoArray[0]).longValue());
            e**Customer.setCustomerType(Long.valueOf(infoArray[4]).longValue());
            e**Customer.setCustomerName(infoArray[2]);
            e**Customer.setCustomerMobile(infoArray[3]);
            e**Customer.setCredentialType(Long.valueOf(infoArray[5]).longValue());
            e**Customer.setCredentialNo(infoArray[6]);
            e**Customer.setStatus(Long.valueOf(infoArray[15]).longValue());
            e**Customer.setDelFlag(0L);

            //on duplicate key update: 如果插入的数据会导致UNIQUE 索引或PRIMARY KEY发生冲突/重复,则执行UPDATE语句
//            e**CustomerMapper.insertDuplicateKeyUpdate(etcCustomer);

            //insert ignore into: 如果插入的数据会导致UNIQUE索引或PRIMARY KEY发生冲突/重复,则忽略此次操作/不插入数据
            e**CustomerMapper.insertIgnore(etcCustomer);

            //replace into: 如果插入的数据会导致UNIQUE索引 或 PRIMARY KEY 发生冲突/重复,则先删除旧数据,再插入最新的数据
//          e**CustomerMapper.insertReplaceInto(etcCustomer);
        }
        br.close();
        long end = System.currentTimeMillis(); //程序执行后的时间戳
        System.out.println("程序执行花费时间:" + (end - start));
    }


}

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think>我们已经在前面的对话中讨论了ONDUPLICATEKEYUPDATE的使用方法,现在用户明确要求查询这个功能的具体实现。用户问题:查找MySQL插入数据时如果数据已存在更新的实现方法,具体提到了"onduplicatekeyupdate"根据先前的知识:1.ONDUPLICATEKEYUPDATE是MySQL中的一种语法,用于在插入数据时,如果触发了唯一索引(包括主键)冲突,则执行更新操作。2.其基本语法为:INSERTINTOtable(column_list)VALUES(value_list)ONDUPLICATEKEYUPDATEcolumn1=value1,column2=value2,...;3.需要注意的是,这个语句依赖于表上的唯一索引主键。如果插入的数据导致唯一索引(主键)冲突,则更新指定的列;否则,就插入新行。4.在UPDATE子句中,我们可以使用VALUES(column)函数来引用原本打算插入的值,避免重复书写。5.这个操作会使得受影响的行数返回值为:如果插入新行则为1;如果更新已有行则为2(因为更新操作实际上是删除旧行再插入新行?但实际上MySQL更新是原地更新,但受影响行数会有特殊计数);如果更新前后的数据完全一样,则受影响行数为0(但有些版本可能有同)。6.此外,还有REPLACEINTO语句也可以实现类似的功能,但它是先删除旧行再插入新行,可能会导致自增主键连续,并且会删除旧行(可能触发删除触发器)再插入新行(触发插入触发器),而ONDUPLICATEKEYUPDATE只会触发更新触发器。7.由于用户明确要求ONDUPLICATEKEYUPDATE,所以我们重点介绍这个方法。接下来,我们将按照用户需求,给出一个具体的示例和详细说明。注意:在回答中,我们要使用LaTeX格式的数学表达式(虽然这个问题可能涉及较少数学,但如果有变量等,要按照要求格式化)。</think> MySQL 中的 `ON DUPLICATE KEY UPDATE` 语法是解决"插入存在更新"的标准方案。以下是具体实现方法和技术解析: ### 📌 实现语法 ```sql INSERT INTO 表名 (列1, 列2, 列3) VALUES (值1, 值2, 值3) ON DUPLICATE KEY UPDATE 列2 = VALUES(列2), -- 使用插入更新 列3 = 表达式; -- 使用表达式更新 ``` ### 🔑 核心机制 1. **依赖唯一约束** 必须存在唯一索引(`UNIQUE` `PRIMARY KEY`)才会触发更新,否则总是插入新数据[^1] ```sql -- 示例表结构(必需唯一索引) CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(50), login_count INT DEFAULT 0, UNIQUE KEY (name) -- 唯一约束触发点 ); ``` 2. **原子性操作** 在检测到唯一键冲突时自动转为更新操作,保证原子性: - 存在冲突 → 执行 `UPDATE` - 无冲突 → 执行 `INSERT` ### 🚀 实操示例 ```sql -- 插入新用户更新登录次数 INSERT INTO users (id, name, login_count) VALUES (1, 'Alice', 1) ON DUPLICATE KEY UPDATE login_count = login_count + VALUES(login_count); -- 结果说明: -- 首次执行 ⇒ 插入新记录 (login_count=1) -- 后续执行 ⇒ 更新记录 (login_count+1) ``` ### ⚠️ 注意事项 1. **特殊返回值** ```markdown - 插入成功: Affected rows = 1 - 更新成功: Affected rows = 2 - 值无变化: Affected rows = 0 ``` 2. **自增ID跳跃** 更新操作会使 `AUTO_INCREMENT` 值增长,即使未实际插入新数据。 3. **多唯一键处理** 若存在多个唯一索引,任意一个冲突都会触发更新,优先主键冲突[^2]。 ### 🔁 替代方案对比 | 方法 | 特点 | |-----------------------------|----------------------------------| | `REPLACE INTO` | 先删除旧记录再插入,丢失关联数据 | | `INSERT IGNORE` | 忽略冲突更新 | | 先查询后更新 | 存在并发安全风险 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值