mybatis 批量插入mysql数据并根据唯一索引做自动去重判断的插入语句

本文介绍如何使用MyBatis操作MySQL数据库实现批量插入数据,并通过唯一索引判断数据是否重复,若重复则更新,不重复则新增。具体包括在DAO层定义批量插入方法,及在XML中实现具体的SQL语句。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:

此处为mybatis 操作mysql数据库实现批量插入。再根据表的唯一索引来判断数据是否重复,如果重复则更新,如果不重复则新增的xml写法

注意:

首先在表中创建可以确认数据唯一性的唯一索引:

例如:UNIQUE KEY `unionIndex` (`keyword_id`,`the_day`) USING BTREE,

dao层

import com.rrc.marketing.core.po.sem.SemKeywordReportBaiduEntity;
import com.rrc.marketing.core.po.sem.SemKeywordTypeBaiduEntity;
import com.rrc.marketing.core.util.MyMapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @Auther:qixin
 * @Date: 2018/10/28 14:52
 * @Description:
 */
public interface SemKeywordReportBaiduDao extends MyMapper<SemKeywordReportBaiduEntity> {
    //批量插入并去重
    void duplicateInsertList(@Param("semKeywordReportBaiduEntityList") List<SemKeywordReportBaiduEntity> semKeywordReportBaiduEntityList);
}

然后再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.rrc.marketing.core.dao.sem.SemKeywordReportBaiduDao" >

    <insert id="duplicateInsertList" parameterType="java.util.List">
        INSERT INTO sem_keyword_report_baidu (
        fr, channel_id, channel_name,
        account_id, account_name, campaign_id,
        campaign_name,campaign_city,
        adgroup_id, adgroup_name,
        keyword_id,keyword,
        cost,cost_real,click,impression,
        device,report_level,report_type,
        the_day,the_week,the_month,
        version,create_date,update_date
        )VALUES
        <foreach collection="semKeywordReportBaiduEntityList" item="item" index="index" separator=",">
            (
            #{item.fr,jdbcType=VARCHAR}, #{item.channelId,jdbcType=INTEGER}, #{item.channelName,jdbcType=VARCHAR},
            #{item.accountId,jdbcType=BIGINT}, #{item.accountName,jdbcType=VARCHAR}, #{item.campaignId,jdbcType=BIGINT},
            #{item.campaignName,jdbcType=VARCHAR},#{item.campaignCity,jdbcType=VARCHAR},
            #{item.adgroupId,jdbcType=BIGINT}, #{item.adgroupName,jdbcType=VARCHAR},
            #{item.keywordId,jdbcType=BIGINT}, #{item.keyword,jdbcType=VARCHAR},
            #{item.cost,jdbcType=DECIMAL},#{item.costReal,jdbcType=DECIMAL},#{item.click,jdbcType=INTEGER},#{item.impression,jdbcType=INTEGER},
            #{item.device,jdbcType=VARCHAR},#{item.reportLevel,jdbcType=INTEGER},#{item.reportType,jdbcType=INTEGER},
            #{item.theDay,jdbcType=VARCHAR},#{item.theWeek,jdbcType=VARCHAR},#{item.theMonth,jdbcType=VARCHAR},
            #{item.version,jdbcType=INTEGER}, #{item.createDate,jdbcType=TIMESTAMP},#{item.updateDate,jdbcType=TIMESTAMP}
            )
        </foreach>
        ON DUPLICATE KEY UPDATE
        fr = VALUES(fr),channel_id = VALUES(channel_id),channel_name = VALUES(channel_name),
        account_id = VALUES(account_id),account_name = VALUES(account_name),campaign_id = VALUES(campaign_id),
        campaign_name = VALUES(campaign_name),campaign_city = VALUES(campaign_city),adgroup_id = VALUES(adgroup_id),adgroup_name = VALUES(adgroup_name),
        keyword = VALUES(keyword),cost = VALUES(cost),cost_real = VALUES(cost_real),
        click = VALUES(click),impression = VALUES(impression),device = VALUES(device),
        report_level = VALUES(report_level),report_type = VALUES(report_type),the_day = VALUES(the_day),
        the_week = VALUES(the_week),the_month = VALUES(the_month),version = VALUES(version),
        create_date = VALUES(create_date),update_date = VALUES(update_date)
    </insert>

</mapper>

感谢观看

<think>好的,我现在需要帮用户解决在Java中实现大数据插入操作根据ID和messageid的问题。首先,我得理解用户的具体需求。用户提到“大数据量”,所以性能肯定是关键,同要避免数据插入复的条件是ID和messageid的组合。数据库方面,可能用的是MySQL或者其他关系型数据库,但用户没有明确说明,可能需要一些通用处理。 首先,我需要考虑的策略。常见的方法有数据唯一索引、在插入前查询是否存在、或者使用临表/中间表进行批量。对于大数据量来说,逐条查询是否存在显然效率低下,应该避免。因此,数据库层面的唯一索引可能是个好办法,但需要用户确认是否可以在ID和messageid上建立唯一约束。如果数据库已经存在唯一索引,那么插入数据会抛出异常,这候可以在Java中捕获异常处理,但这种方式在大数据可能会影响性能,因为每次冲突都会导致异常处理的开销。 另一种方法是使用批处理,且在插入前进行。比如,使用INSERT INTO ... ON DUPLICATE KEY UPDATE或者MERGE语句(取决于数据库类型)。例如,MySQL支持ON DUPLICATE KEY UPDATE,而Oracle则使用MERGE。不过,这需要数据库支持这些语法,且需要建立唯一索引。 用户提到使用MyBatis,所以可能需要用到MyBatis批量插入功能。例如,使用foreach标签拼接SQL,但需要注意SQL长度限制。此外,结合数据库的唯一索引,可以在插入忽略复记录,比如使用INSERT IGNORE(MySQL)或者ON CONFLICT DO NOTHING(PostgreSQL)。不过这些语法是数据库特定的,用户需要根据使用的数据库调整。 另外,用户参考了引用[2]中的建议,提到使用EasyExcel处理数据导入,结合线程池提高效率。可能用户的数据来源是Excel文件,需要先解析处理数据,再进行插入。因此,在数据预处理阶段,可以在内存中对ID和messageid进行,比如使用HashSet或者Java 8的Stream API的distinct()方法。但要注意,如果数据量极大,内存可能不足,这候可能需要分批次处理,或者使用外部排序。 还有一个考虑是使用数据库的临表。先将数据批量插入表,然后通过SQL语句将临表中的数据插入到目标表。这种方法可以减少应用层的处理压力,但需要额外的数据库操作。 关于性能优化,引用[2]提到使用MyBatis的foreach批量插入,而不是多次单条插入。这确实能减少数据库连接的开销,提高效率。同,结合批处理的大小,比如每1000条提交一次,避免一次性提交过多数据导致内存或数据库事务问题。 另外,线程池的使用也很要。在数据处理和插入过程中,可以利用多线程行处理,但需要注意线程安全和数据库连接池的配置,避免资源竞争和连接不足的问题。 关于的具体实现步骤,可能需要分几个阶段:首先在应用层对数据进行初步,比如在读取数据就过滤掉复的ID和messageid组合;然后,在插入数据,利用数据库的唯一索引来保证最终的。这种双检查机制可以提高效率,减少数据库的负担。 还需要考虑事务管理。如果插入操作需要事务支持,确保在批处理中正确管理事务,比如每个批次一个事务,避免一个超大事务导致锁表或日志膨胀。 最后,异常处理也很要。在插入过程中,可能会遇到复键异常,需要捕获记录这些情况,而不是让整个批处理失败。可以记录复的数据,后续进行人工核查或者其他处理。 总结一下,可能的解决方案步骤是: 1. 在数据库的表中为ID和messageid创建联合唯一索引。 2. 在Java应用中,使用EasyExcel等工具读取数据在读取进行初步。 3. 将数据分批次处理,每批次使用MyBatis的foreach进行批量插入。 4. 使用INSERT语句的ON DUPLICATE KEY UPDATE或类似语法,避免插入复记录。 5. 配置合适的线程池,行处理数据读取和插入,提高效率。 6. 处理可能的异常,记录数据,确保程序健壮性。 需要验证的是,不同数据库对唯一索引插入语法的支持情况,以及批处理的最佳实践,比如批次大小的调整,避免数据库的max_allowed_packet限制等问题。此外,测试不同数据量下的性能表现,优化线程池参数和批处理大小,以达到最佳性能。</think>在Java中实现大数据插入操作,需结合数据库特性和代码优化策略实现高效。以下是分步实现方案: --- ### **步骤1:数据库表设计优化** 在数据库表中为`ID`和`messageid`字段创建**联合唯一索引**,确保数据库层面直接拦截数据: ```sql ALTER TABLE your_table ADD UNIQUE INDEX idx_unique_id_messageid (id, messageid); ``` 此索引会直接拒绝复记录的插入[^1]。 --- ### **步骤2:数据预处理** 使用Java集合类或流式处理对数据预先: ```java // 使用HashSet过滤复的(id, messageid)组合 Set<String> uniqueKeys = new HashSet<>(); List<DataEntity> filteredData = rawData.stream() .filter(entity -> uniqueKeys.add(entity.getId() + "#" + entity.getMessageid())) .collect(Collectors.toList()); ``` --- ### **步骤3:分批次批量插入** 通过MyBatis的`foreach`标签实现高效批量插入,每批处理1000-5000条记录: ```xml <insert id="batchInsert" parameterType="java.util.List"> INSERT INTO your_table (id, messageid, other_columns) VALUES <foreach collection="list" item="item" separator=","> (#{item.id}, #{item.messageid}, #{item.otherColumns}) </foreach> ON DUPLICATE KEY UPDATE id = id -- MySQL语法,冲突忽略 </insert> ``` - **MySQL**使用`ON DUPLICATE KEY UPDATE`[^1] - **PostgreSQL**使用`ON CONFLICT (id, messageid) DO NOTHING` - **Oracle**使用`MERGE`语句 --- ### **步骤4:异步多线程处理** 结合线程池提高处理效率(引用[2]优化建议): ```java // 使用自定义线程池处理数据分片 ExecutorService executor = Executors.newFixedThreadPool(8); List<CompletableFuture<Void>> futures = new ArrayList<>(); List<List<DataEntity>> chunks = Lists.partition(filteredData, 1000); for (List<DataEntity> chunk : chunks) { futures.add(CompletableFuture.runAsync(() -> yourMapper.batchInsert(chunk), executor)); } CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); ``` --- ### **步骤5:性能监控与调优** - 使用`jstack`和`jmap`监控线程阻塞或内存泄漏(引用[3]) - 调整批次大小和线程池参数,避免数据库连接池耗尽 - 数据库侧开启慢查询日志,优化索引命中率 --- ### **异常处理建议** ```java try { yourMapper.batchInsert(dataChunk); } catch (DuplicateKeyException e) { // 记录数据或忽略 log.warn("Duplicate records skipped: {}", e.getMessage()); } ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值