杰瑞科技汇

Java如何将Excel数据高效导入数据库?

  • Excel 操作: Apache POI
  • 数据库连接: JDBC (以 MySQL 为例)
  • 数据库操作: JDBI (一个轻量级的 SQL 查询和访问库,可以让你用更优雅的方式操作 JDBC)

第一步:环境准备

添加依赖

在你的 Maven 项目的 pom.xml 文件中,添加以下依赖,请根据你的数据库类型(如 Oracle, PostgreSQL)修改 JDBC 驱动的版本和坐标。

Java如何将Excel数据高效导入数据库?-图1
(图片来源网络,侵删)
<dependencies>
    <!-- 1. Apache POI: 用于操作 Excel 文件 -->
    <!-- 注意:这里包含了 xlsx (OOXML) 和 xls (BIFF) 格式的支持 -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.2.3</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.3</version>
    </dependency>
    <!-- 2. MySQL JDBC Driver: 用于连接 MySQL 数据库 -->
    <!-- 如果你使用其他数据库,请替换为相应的驱动,如 oracle.jdbc.driver.OracleDriver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
    </dependency>
    <!-- 3. JDBI: 一个轻量级的 SQL 访问库,简化 JDBC 操作 -->
    <dependency>
        <groupId>org.jdbi</groupId>
        <artifactId>jdbi3-core</artifactId>
        <version>3.36.0</version>
    </dependency>
    <dependency>
        <groupId>org.jdbi</groupId>
        <artifactId>jdbi3-sqlobject</artifactId>
        <version>3.36.0</version>
    </dependency>
</dependencies>

准备 Excel 文件

假设我们有一个名为 students.xlsx 的文件,内容如下:

id name age email
1 张三 20 zhangsan@example.com
2 李四 21 lisi@example.com
3 王五 22 wangwu@example.com

准备数据库表

在你的 MySQL 数据库中,创建一个对应的表。

CREATE DATABASE IF NOT EXISTS test_db;
USE test_db;
CREATE TABLE IF NOT EXISTS students (
    id INT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    age INT,
    email VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

第二步:核心代码实现

我们将代码分为几个部分,使结构更清晰。

数据库连接配置

创建一个工具类来管理数据库连接。

Java如何将Excel数据高效导入数据库?-图2
(图片来源网络,侵删)
import org.jdbi.v3.core.Jdbi;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseConfig {
    // 数据库连接信息
    private static final String URL = "jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root"; // 你的数据库用户名
    private static final String PASSWORD = "password"; // 你的数据库密码
    /**
     * 获取原始的 JDBC 连接
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }
    /**
     * 获取 JDBI 实例
     */
    public static Jdbi getJdbi() {
        return Jdbi.create(URL, USER, PASSWORD);
    }
}

定义数据模型

创建一个 Java 类来映射 Excel 中的每一行数据。

public class Student {
    private int id;
    private String name;
    private int age;
    private String email;
    // Getters and Setters
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

Excel 数据读取与数据库导入服务

这是核心逻辑部分,我们将读取 Excel 并将数据批量插入数据库。

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ExcelImportService {
    /**
     * 从 Excel 文件读取学生数据
     * @param filePath Excel 文件路径
     * @return 学生列表
     */
    public List<Student> readStudentsFromExcel(String filePath) throws IOException {
        List<Student> students = new ArrayList<>();
        FileInputStream fis = new FileInputStream(new File(filePath));
        Workbook workbook = new XSSFWorkbook(fis); // 针对 .xlsx 文件
        // Workbook workbook = new HSSFWorkbook(fis); // 针对 .xls 文件
        Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表
        // 假设第一行是标题,从第二行开始读取数据
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                continue; // 跳过空行
            }
            Student student = new Student();
            student.setId((int) row.getCell(0).getNumericCellValue());
            student.setName(row.getCell(1).getStringCellValue());
            student.setAge((int) row.getCell(2).getNumericCellValue());
            // 处理可能为空的单元格
            Cell emailCell = row.getCell(3);
            if (emailCell != null) {
                student.setEmail(emailCell.getStringCellValue());
            }
            students.add(student);
        }
        workbook.close();
        fis.close();
        return students;
    }
    /**
     * 将学生列表批量导入数据库
     * @param students 学生列表
     */
    public void importStudentsToDatabase(List<Student> students) {
        Jdbi jdbi = DatabaseConfig.getJdbi().installPlugin(new SqlObjectPlugin());
        // 使用 JDBI 的 SQL Object 接口来定义数据库操作
        StudentDao studentDao = jdbi.onDemand(StudentDao.class);
        // 开始事务
        jdbi.useTransaction(handle -> {
            // 先清空表(可选,根据业务需求)
            // handle.attach(StudentDao.class).deleteAll();
            // 批量插入
            for (Student student : students) {
                studentDao.insert(student);
            }
        });
    }
    // 主方法,用于测试
    public static void main(String[] args) {
        ExcelImportService service = new ExcelImportService();
        try {
            // 1. 从 Excel 读取数据
            List<Student> students = service.readStudentsFromExcel("students.xlsx");
            System.out.println("成功从 Excel 读取到 " + students.size() + " 条数据。");
            // 2. 将数据导入数据库
            service.importStudentsToDatabase(students);
            System.out.println("数据成功导入数据库!");
        } catch (IOException e) {
            System.err.println("读取 Excel 文件失败: " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            System.err.println("导入数据库失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

JDBI DAO 接口

创建一个接口,用于定义与 students 表的交互。

import org.jdbi.v3.sqlobject.SqlObject;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
// 告诉 JDBI 如何将 Student 类映射到数据库列
@RegisterBeanMapper(Student.class)
public interface StudentDao extends SqlObject {
    // 插入一条学生记录
    @SqlUpdate("INSERT INTO students (id, name, age, email) VALUES (:id, :name, :age, :email)")
    void insert(Student student);
    // 可选:清空表
    @SqlUpdate("TRUNCATE TABLE students")
    void deleteAll();
}

第三步:代码解析与最佳实践

代码解析

  • ExcelImportService: 这是核心服务类,它负责协调“读取Excel”和“导入数据库”两个步骤。
  • readStudentsFromExcel:
    • 使用 XSSFWorkbook 来处理 .xlsx 格式,如果是旧的 .xls 格式,需要使用 HSSFWorkbook
    • 通过 Sheet.getLastRowNum() 获取总行数。
    • 通过 Row.getCell(index) 获取单元格数据。
    • 重要: getNumericCellValue() 用于数字和日期,getStringCellValue() 用于文本,对于混合类型或有空值的单元格,需要更健壮的处理逻辑(使用 Cell.getCellType() 判断)。
  • importStudentsToDatabase:
    • 使用 Jdbi.onDemand() 获取一个 DAO 接口的实例,它会在每次调用时自动管理连接。
    • jdbi.useTransaction(handle -> ...) 这是关键,它将所有数据库操作包裹在一个事务中,如果其中任何一步失败,整个操作会回滚,保证数据的一致性。
    • 通过循环调用 studentDao.insert() 来逐条插入,对于大量数据,可以考虑使用 JDBI 的批量插入功能,性能会更高。

最佳实践与注意事项

  1. 事务管理: 永远不要忘记使用事务! 这确保了数据导入的原子性,要么全部成功,要么全部失败,避免数据部分导入导致的数据不一致。

    Java如何将Excel数据高效导入数据库?-图3
    (图片来源网络,侵删)
  2. 性能优化 (批量插入):

    • 上述代码是逐条插入,对于几千条数据可能没问题,但如果数据量达到上万或百万,性能会非常差。
    • 优化方案: 使用 JDBC 的 addBatch()executeBatch(),JDBI 也支持此功能,你需要修改 DAO 接口和导入逻辑。

    优化后的 DAO 接口:

    @SqlBatch("INSERT INTO students (id, name, age, email) VALUES (:id, :name, :age, :email)")
    void insertBatch(List<Student> students);

    优化后的导入逻辑:

    // 在 importStudentsToDatabase 方法中
    // ...
    studentDao.insertBatch(students); // 一次性批量插入
    // ...

    批量插入能极大地减少与数据库的交互次数,是大数据量导入的标准做法。

  3. 异常处理:

    • 代码中使用了 try-catch 来捕获 IOException 和其他 Exception,在实际应用中,应该更精细地处理异常,例如区分文件不存在、格式错误、数据库连接失败、数据约束冲突(如主键重复)等,并给出不同的用户提示。
  4. 数据校验:

    • 在导入前,应对从 Excel 读取的数据进行校验,检查 email 格式是否合法,age 是否在合理范围内,id 是否重复等,可以在 readStudentsFromExcel 方法中增加校验逻辑,或者在插入前进行统一校验。
  5. 内存管理:

    • Workbook 对象可能占用大量内存,特别是对于大型 Excel 文件,使用完毕后,务必调用 workbook.close()fis.close() 来释放资源,更好的方式是使用 try-with-resources 语句。
      try (FileInputStream fis = new FileInputStream(new File(filePath));
       Workbook workbook = new XSSFWorkbook(fis)) {
      // ... 处理逻辑 ...
      } catch (IOException e) {
      // ...
      }
  6. 通用性与灵活性:

    如果需要导入不同结构的 Excel 文件到不同的表,可以设计一个更通用的框架,通过配置文件(如 JSON, XML)来映射 Excel 列、数据类型和数据库字段。

通过以上步骤和最佳实践,你就可以构建一个健壮、高效的 Java Excel 导入数据库功能。

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