杰瑞科技汇

Java Excel导入Oracle数据如何高效实现?

  1. 读取Excel文件:使用一个库(如Apache POI)来解析Excel文件,逐行读取数据。
  2. 处理数据:将读取到的数据(通常是字符串)进行校验、转换(如日期、数字格式)。
  3. 批量插入数据库:使用JDBC(Java Database Connectivity)连接Oracle数据库,将处理好的数据高效地批量插入。

下面我将提供一个完整的、分步的指南,包含代码示例和最佳实践。

Java Excel导入Oracle数据如何高效实现?-图1
(图片来源网络,侵删)

第一步:准备工作

添加依赖

你需要在你的项目中添加两个核心库的依赖:Apache POI (用于操作Excel) 和 Oracle JDBC Driver (用于连接Oracle数据库)。

如果你使用 Maven,在 pom.xml 中添加以下依赖:

<!-- Apache POI for Excel operations -->
<dependencies>
    <!-- POI Core -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.2.5</version> <!-- 建议使用较新稳定版本 -->
    </dependency>
    <!-- POI for OOXML format (.xlsx) -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.5</version>
    </dependency>
    <!-- Oracle JDBC Driver -->
    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>19.3.0.0</version> <!-- 请根据你的Oracle客户端版本选择 -->
    </dependency>
</dependencies>

如果你使用 Gradle,在 build.gradle 中添加:

dependencies {
    // Apache POI for Excel operations
    implementation 'org.apache.poi:poi:5.2.5'
    implementation 'org.apache.poi:poi-ooxml:5.2.5'
    // Oracle JDBC Driver
    implementation 'com.oracle.database.jdbc:ojdbc8:19.3.0.0'
}

准备Oracle表和数据

假设我们有一个Excel文件,内容如下,我们想将其导入到Oracle的 EMPLOYEES 表中。

Java Excel导入Oracle数据如何高效实现?-图2
(图片来源网络,侵删)

Excel (employees.xlsx) 内容示例:

ID NAME EMAIL HIRE_DATE SALARY
101 张三 zhangsan@example.com 2025-01-15 8000
102 李四 lisi@example.com 2025-02-20 9500
103 王五 wangwu@example.com 2025-03-10 12000

Oracle 表结构 (EMPLOYEES):

CREATE TABLE EMPLOYEES (
    ID          NUMBER(10) PRIMARY KEY,
    NAME        VARCHAR2(100) NOT NULL,
    EMAIL       VARCHAR2(100) UNIQUE,
    HIRE_DATE   DATE,
    SALARY      NUMBER(10, 2)
);

第二步:编写Java代码

我们将创建一个Java类来完成这个任务,代码将分为几个部分:

  1. 数据库连接工具类:封装获取数据库连接的逻辑。
  2. Excel导入主逻辑类:读取Excel、处理数据、批量插入。

数据库连接工具类 (DBUtil.java)

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
    // 替换为你的实际数据库连接信息
    private static final String URL = "jdbc:oracle:thin:@your_host:your_port:your_service_name";
    private static final String USER = "your_username";
    private static final String PASSWORD = "your_password";
    // 静态代码块,加载驱动
    static {
        try {
            Class.forName("oracle.jdbc.OracleDriver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("Failed to load Oracle JDBC driver", e);
        }
    }
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }
    public static void closeConnection(Connection conn) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

Excel导入主逻辑类 (ExcelImportToOracle.java)

这是核心代码,包含了详细的注释。

Java Excel导入Oracle数据如何高效实现?-图3
(图片来源网络,侵删)
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExcelImportToOracle {
    public static void main(String[] args) {
        // 1. 定义Excel文件路径
        String excelFilePath = "path/to/your/employees.xlsx"; // 替换为你的Excel文件路径
        // 2. 定义Oracle表对应的SQL插入语句
        // 使用 ? 作为占位符,防止SQL注入
        String insertSql = "INSERT INTO EMPLOYEES (ID, NAME, EMAIL, HIRE_DATE, SALARY) VALUES (?, ?, ?, ?, ?)";
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            // 3. 获取数据库连接
            conn = DBUtil.getConnection();
            // 4. 关闭自动提交,开启事务,确保数据一致性
            conn.setAutoCommit(false);
            // 5. 创建PreparedStatement对象
            pstmt = conn.prepareStatement(insertSql);
            // 6. 读取Excel文件
            FileInputStream fis = new FileInputStream(new File(excelFilePath));
            Workbook workbook = new XSSFWorkbook(fis); // 针对 .xlsx 格式
            Sheet sheet = workbook.getSheetAt(0); // 获取第一个Sheet
            // 定义日期格式化器
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            DataFormatter dataFormatter = new DataFormatter(); // 用于读取单元格原始字符串值
            // 7. 遍历Excel行 (从第二行开始,跳过表头)
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    continue; // 跳过空行
                }
                // 8. 从单元格中获取数据并设置到PreparedStatement中
                // ID
                Cell idCell = row.getCell(0);
                int id = (int) idCell.getNumericCellValue();
                pstmt.setInt(1, id);
                // NAME
                Cell nameCell = row.getCell(1);
                String name = dataFormatter.formatCellValue(nameCell); // 使用DataFormatter获取字符串
                pstmt.setString(2, name);
                // EMAIL
                Cell emailCell = row.getCell(2);
                String email = dataFormatter.formatCellValue(emailCell);
                pstmt.setString(3, email);
                // HIRE_DATE
                Cell hireDateCell = row.getCell(3);
                Date hireDate = null;
                if (hireDateCell.getCellType() == CellType.NUMERIC) {
                    // 处理Excel中日期存储为数字的情况
                    if (DateUtil.isCellDateFormatted(hireDateCell)) {
                        hireDate = hireDateCell.getDateCellValue();
                    }
                } else if (hireDateCell.getCellType() == CellType.STRING) {
                    // 处理Excel中日期存储为字符串的情况
                    String dateStr = dataFormatter.formatCellValue(hireDateCell);
                    hireDate = sdf.parse(dateStr);
                }
                if (hireDate != null) {
                    pstmt.setDate(4, new java.sql.Date(hireDate.getTime()));
                } else {
                    pstmt.setNull(4, java.sql.Types.DATE);
                }
                // SALARY
                Cell salaryCell = row.getCell(4);
                BigDecimal salary = BigDecimal.valueOf(salaryCell.getNumericCellValue());
                pstmt.setBigDecimal(5, salary);
                // 9. 添加到批处理中
                pstmt.addBatch();
            }
            // 10. 执行批处理
            int[] result = pstmt.executeBatch();
            System.out.println("成功插入 " + result.length + " 条数据。");
            // 11. 提交事务
            conn.commit();
            System.out.println("事务已提交。");
        } catch (Exception e) {
            // 12. 发生异常时,回滚事务
            try {
                if (conn != null) {
                    conn.rollback();
                    System.err.println("发生异常,事务已回滚。");
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            // 13. 释放资源
            try {
                if (pstmt != null) pstmt.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

第三步:最佳实践与优化

上面的代码是一个基础版本,在生产环境中,你需要考虑更多因素:

性能优化:批处理

上面的代码已经使用了 addBatch()executeBatch(),这是批量插入数据最关键的性能优化点,相比逐条执行SQL,批处理能极大地减少网络I/O和数据库解析开销。

你还可以调整批处理大小,例如每1000条提交一次批处理并刷新,以避免内存占用过大。

// 在循环内部
if (i % 1000 == 0) {
    pstmt.executeBatch();
    conn.commit(); // 可选:每1000条提交一次,减少事务大小
    pstmt.clearBatch();
}

数据校验与错误处理

  • 空值检查:在读取Excel单元格时,检查是否为 null 或空字符串。
  • 类型转换:使用 try-catch 包裹类型转换逻辑,防止因Excel数据格式错误(如期望数字但得到文本)导致程序崩溃。
  • 业务规则校验:检查邮箱格式是否合法,薪资是否为正数等。
  • 记录错误:将不符合规则的数据行号和错误信息记录到日志文件或另一个错误表中,方便后续人工处理。

内存管理

对于非常大的Excel文件(例如几十万行),一次性将整个文件加载到内存(new XSSFWorkbook(fis))可能会导致 OutOfMemoryError

解决方案:使用SAX Event API (XSSF and SAX)

Apache POI提供了基于SAX的API,它以流的方式读取Excel,不会一次性加载整个文件到内存,非常适合处理大文件。

使用这个API需要额外添加依赖:

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>5.2.5</version>
</dependency>

然后使用 XSSFReaderSAXParser 来解析文件,逻辑会比 XSSFWorkbook 复杂一些,但能解决内存问题。

资源释放

try-with-resources 是Java 7引入的语法糖,可以更优雅地确保资源(如文件流、数据库连接)被自动关闭,即使在发生异常时也能正确释放。

// 修改后的文件读取和数据库连接部分
try (Connection conn = DBUtil.getConnection();
     FileInputStream fis = new FileInputStream(new File(excelFilePath));
     Workbook workbook = new XSSFWorkbook(fis)) {
    conn.setAutoCommit(false);
    // ... 其他逻辑 ...
} catch (Exception e) {
    // ... 异常处理 ...
}

注意:PreparedStatement 会在 Connection 关闭时自动关闭,所以不需要单独处理。


将Excel导入Oracle数据库是一个标准化的流程,关键在于选择合适的工具(POI + JDBC)并遵循良好的编程实践。

  1. 选择工具:Apache POI用于读Excel,JDBC用于连Oracle。
  2. 核心流程:读Excel -> 处理数据 -> 批量JDBC插入。
  3. 性能关键:务必使用JDBC的 addBatch() / executeBatch()
  4. 健壮性关键:做好数据校验、异常捕获和事务管理。
  5. 大文件处理:对于超大文件,考虑使用POI的SAX Event API来节省内存。

希望这个详细的指南能帮助你完成Java Excel导入Oracle的任务!

分享:
扫描分享到社交APP
上一篇
下一篇