- Excel 操作: Apache POI
- 数据库连接: JDBC (以 MySQL 为例)
- 数据库操作: JDBI (一个轻量级的 SQL 查询和访问库,可以让你用更优雅的方式操作 JDBC)
第一步:环境准备
添加依赖
在你的 Maven 项目的 pom.xml 文件中,添加以下依赖,请根据你的数据库类型(如 Oracle, PostgreSQL)修改 JDBC 驱动的版本和坐标。

<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 | |
|---|---|---|---|
| 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
);
第二步:核心代码实现
我们将代码分为几个部分,使结构更清晰。
数据库连接配置
创建一个工具类来管理数据库连接。

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 的批量插入功能,性能会更高。
- 使用
最佳实践与注意事项
-
事务管理: 永远不要忘记使用事务! 这确保了数据导入的原子性,要么全部成功,要么全部失败,避免数据部分导入导致的数据不一致。
(图片来源网络,侵删) -
性能优化 (批量插入):
- 上述代码是逐条插入,对于几千条数据可能没问题,但如果数据量达到上万或百万,性能会非常差。
- 优化方案: 使用 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); // 一次性批量插入 // ...
批量插入能极大地减少与数据库的交互次数,是大数据量导入的标准做法。
-
异常处理:
- 代码中使用了
try-catch来捕获IOException和其他Exception,在实际应用中,应该更精细地处理异常,例如区分文件不存在、格式错误、数据库连接失败、数据约束冲突(如主键重复)等,并给出不同的用户提示。
- 代码中使用了
-
数据校验:
- 在导入前,应对从 Excel 读取的数据进行校验,检查
email格式是否合法,age是否在合理范围内,id是否重复等,可以在readStudentsFromExcel方法中增加校验逻辑,或者在插入前进行统一校验。
- 在导入前,应对从 Excel 读取的数据进行校验,检查
-
内存管理:
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) { // ... }
-
通用性与灵活性:
如果需要导入不同结构的 Excel 文件到不同的表,可以设计一个更通用的框架,通过配置文件(如 JSON, XML)来映射 Excel 列、数据类型和数据库字段。
通过以上步骤和最佳实践,你就可以构建一个健壮、高效的 Java Excel 导入数据库功能。
