构建一个高性能的通用批量插入工具-Oracle版

Oracle + MyBatis 通用高性能批量导入框架(企业级完整版)

一、设计目标

适用于:

  • SpringBoot

  • MyBatis / MyBatisPlus

  • Oracle 数据库

  • Excel 导入

  • 大批量数据(2万 ~ 百万级)

目标:

  • 高性能

  • 通用化

  • 可复用

  • 支持任意实体

  • 自动分批

  • 事务控制

  • 导入失败定位

  • 导入耗时统计

  • 支持以后所有批量导入业务


二、推荐方案(核心思想)

采用:

Excel
  ↓
实体List
  ↓
通用BatchUtils自动分批
  ↓
MyBatis XML foreach + UNION ALL
  ↓
Oracle

Oracle 最适合:

INSERT INTO TABLE_NAME
SELECT ... FROM DUAL
UNION ALL
SELECT ... FROM DUAL

不要使用:

saveBatch()

因为本质仍然是循环 insert。


三、项目结构建议

com.xxx
 ├── batch
 │    ├── BatchUtils.java
 │    ├── BatchResult.java
 │    ├── BatchImportService.java
 │    └── BatchExecutor.java
 │
 ├── mapper
 │    ├── UserMapper.java
 │    └── UserMapper.xml
 │
 ├── entity
 │    └── User.java
 │
 └── service
      └── UserImportService.java

四、通用分批工具类(核心)

BatchUtils.java

package com.xxx.batch;

import java.util.List;
import java.util.function.Consumer;

public class BatchUtils {

    /**
     * 通用分批处理
     */
    public static <T> void batchProcess(
            List<T> dataList,
            int batchSize,
            Consumer<List<T>> consumer) {

        if (dataList == null || dataList.isEmpty()) {
            return;
        }

        int total = dataList.size();

        for (int i = 0; i < total; i += batchSize) {

            int end = Math.min(i + batchSize, total);

            List<T> batchList = dataList.subList(i, end);

            consumer.accept(batchList);
        }
    }
}

五、批量执行结果对象

BatchResult.java

package com.xxx.batch;

import lombok.Data;

@Data
public class BatchResult {

    /**
     * 总数据量
     */
    private int total;

    /**
     * 成功数量
     */
    private int success;

    /**
     * 失败数量
     */
    private int fail;

    /**
     * 耗时(ms)
     */
    private long cost;
}

六、通用批量执行器

BatchExecutor.java

package com.xxx.batch;

import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.function.Consumer;

@Slf4j
public class BatchExecutor {

    /**
     * 默认批次大小
     */
    private static final int DEFAULT_BATCH_SIZE = 500;

    /**
     * 通用批量执行
     */
    public static <T> BatchResult execute(
            List<T> dataList,
            Consumer<List<T>> consumer) {

        return execute(dataList, DEFAULT_BATCH_SIZE, consumer);
    }

    /**
     * 通用批量执行
     */
    public static <T> BatchResult execute(
            List<T> dataList,
            int batchSize,
            Consumer<List<T>> consumer) {

        long start = System.currentTimeMillis();

        BatchResult result = new BatchResult();

        if (dataList == null || dataList.isEmpty()) {
            return result;
        }

        int total = dataList.size();

        result.setTotal(total);

        try {

            BatchUtils.batchProcess(dataList, batchSize, batch -> {
                consumer.accept(batch);
            });

            result.setSuccess(total);
            result.setFail(0);

        } catch (Exception e) {

            log.error("批量执行失败", e);

            result.setSuccess(0);
            result.setFail(total);

            throw e;
        }

        result.setCost(System.currentTimeMillis() - start);

        return result;
    }
}

七、实体类示例

User.java

package com.xxx.entity;

import lombok.Data;

@Data
public class User {

    private Long id;

    private String name;

    private Integer age;
}

八、Mapper 接口

UserMapper.java

package com.xxx.mapper;

import com.xxx.entity.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface UserMapper {

    int batchInsert(@Param("list") List<User> list);
}

九、Oracle 高性能 XML(核心)

UserMapper.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.xxx.mapper.UserMapper">

    <insert id="batchInsert">

        INSERT INTO USER_TABLE
        (
            ID,
            NAME,
            AGE
        )

        <foreach collection="list"
                 item="item"
                 separator="UNION ALL">

            SELECT
                #{item.id},
                #{item.name},
                #{item.age}
            FROM DUAL

        </foreach>

    </insert>

</mapper>

十、Service 层(生产推荐)

UserImportService.java

package com.xxx.service;

import com.xxx.batch.BatchExecutor;
import com.xxx.batch.BatchResult;
import com.xxx.entity.User;
import com.xxx.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserImportService {

    private final UserMapper userMapper;

    /**
     * Excel导入
     */
    @Transactional(rollbackFor = Exception.class)
    public BatchResult importExcel(List<User> list) {

        return BatchExecutor.execute(list, 500, batch -> {

            userMapper.batchInsert(batch);

        });
    }
}

十一、Controller 示例

@PostMapping("/import")
public String importExcel(MultipartFile file) {

    List<User> list = ExcelUtils.parse(file, User.class);

    BatchResult result = userImportService.importExcel(list);

    return "成功导入:" + result.getSuccess();
}

十二、Excel 导入推荐方案

推荐:

方案推荐度
EasyExcel ✅✅✅
POI ⚠ 一般

推荐:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version>
</dependency>

十三、性能优化(非常重要)

1、批次大小推荐

数据量推荐
<1万 500
1~10万 1000
10万+ 2000

2、关闭 SQL 日志

不要开启:

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

会严重影响性能。


3、导入期间关闭索引(超大数据)

如果几十万以上:

删除索引
导入
重建索引

性能提升巨大。


4、避免单次SQL过大

不要:

2万条一次 insert

Oracle SQL 长度有限制。

推荐:

500~1000 一批

十四、通用扩展方案(推荐)

以后你还可以扩展:

  • 导入失败行定位

  • 导入日志表

  • 导入进度条

  • 异步导入

  • MQ导入

  • 导入模板下载

  • 自动字段映射

  • 动态SQL生成

  • 通用 Mapper

  • 插入/更新(UPSERT)

  • 幂等导入


十五、百万级数据推荐方案

如果以后达到:

100万+

推荐:

  • Oracle SQL Loader

  • Data Pump

  • 外部表

  • JDBC Batch

  • 多线程分片导入

而不是 MyBatis。


十六、最终结论(企业项目最佳实践)

推荐最终方案:

EasyExcel
    ↓
List<T>
    ↓
BatchExecutor
    ↓
500分批
    ↓
MyBatis XML foreach
    ↓
Oracle UNION ALL
    ↓
事务提交

这是目前:

  • 最稳定

  • 最通用

  • 最容易维护

  • 性能最高

  • 企业最常用

的一套 Oracle 批量导入方案。

posted @ 2026-05-13 17:41  哩个啷个波  阅读(24)  评论(0)    收藏  举报