当前位置:首页 > 数据库 > 正文

java怎么将excel导入到数据库

Apache POI解析Excel文件,结合JDBC批量执行SQL插入

Java中将Excel文件导入数据库是一个常见的需求,通常涉及使用Apache POI库读取Excel数据,并通过JDBC连接数据库进行插入操作,以下是详细的实现步骤和示例代码:

准备工作

  1. 环境配置

    • 确保已安装Java JDK(建议版本≥8)、IDE工具(如IntelliJ IDEA或Eclipse),以及目标数据库管理系统(例如MySQL)。
    • 如果使用Maven管理项目依赖,需在pom.xml中添加以下库:
      <!-Apache POI用于处理Excel -->
      <dependency>
          <groupId>org.apache.poi</groupId>
          <artifactId>poi-ooxml</artifactId>
          <version>5.2.3</version>
      </dependency>
      <!-MySQL驱动 -->
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.28</version>
      </dependency>
  2. 创建测试用的Excel文件:例如名为data.xlsx的文件,内容包含表头和若干行记录,示例结构如下:
    | ID | Name | Age |
    |—-|———|—–|
    | 1 | Alice | 30 |
    | 2 | Bob | 25 |

  3. 设计数据库表结构:根据Excel的列名创建对应的数据库表,在MySQL中执行:

    CREATE TABLE users (
        id INT PRIMARY KEY,
        name VARCHAR(255),
        age INT
    );

核心实现步骤

读取Excel文件

使用Apache POI解析Excel文件,逐行提取数据,关键点包括:跳过表头行、处理不同类型单元格(字符串/数字等)、避免空值异常,以下是典型代码片段:

import org.apache.poi.ss.usermodel.;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
public class ExcelReader {
    public List<List<Object>> readExcel(String filePath) throws IOException {
        List<List<Object>> dataList = new ArrayList<>();
        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = new XSSFWorkbook(fis)) {
            Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表
            for (Row row : sheet) {
                if (row.getRowNum() == 0) continue; // 跳过表头
                List<Object> rowData = new ArrayList<>();
                for (Cell cell : row) {
                    switch (cell.getCellType()) {
                        case STRING:
                            rowData.add(cell.getStringCellValue());
                            break;
                        case NUMERIC:
                            rowData.add(cell.getNumericCellValue());
                            break;
                        default:
                            rowData.add(null); // 其他类型暂存为null
                    }
                }
                dataList.add(rowData);
            }
        }
        return dataList;
    }
}

注意:上述代码通过判断单元格类型动态适配不同格式的数据,确保数值型字段不会被错误转换为字符串。

连接数据库并插入数据

通过JDBC建立连接后,利用PreparedStatement批量执行SQL语句以提高效率,推荐使用事务管理保证操作的原子性:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
public class DatabaseInserter {
    private static final String URL = "jdbc:mysql://localhost:3306/your_database";
    private static final String USERNAME = "your_username";
    private static final String PASSWORD = "your_password";
    public void insertData(List<List<Object>> rows) throws SQLException {
        try (Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
            String sql = "INSERT INTO users (id, name, age) VALUES (?, ?, ?)";
            try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                for (List<Object> row : rows) {
                    pstmt.setInt(1, (Integer) row.get(0));      // ID列为整数类型
                    pstmt.setString(2, (String) row.get(1));     // Name列为字符串类型
                    pstmt.setInt(3, (Integer) row.get(2));      // Age列为整数类型
                    pstmt.addBatch(); // 添加到批处理队列
                }
                pstmt.executeBatch(); // 一次性执行所有批次操作
            }
        }
    }
}

优化点:①使用批处理(Batch Processing)减少网络交互次数;②显式指定参数类型防止SQL注入攻击;③自动提交事务由JDBC默认机制控制。

整合流程

将上述模块组合成完整的导入程序:

public class MainApp {
    public static void main(String[] args) {
        String excelPath = "src/main/resources/data.xlsx";
        ExcelReader reader = new ExcelReader();
        DatabaseInserter inserter = new DatabaseInserter();
        try {
            List<List<Object>> rows = reader.readExcel(excelPath);
            inserter.insertData(rows);
            System.out.println("成功导入" + rows.size() + "条记录!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

常见问题与解决方案

序号 问题描述 解决方法
1 Excel日期格式解析失败 改用DateUtil.isCellDateFormatted()检测后,通过DateUtil.getJavaDate()转换
2 大数据量导致内存溢出 分块读取Excel(使用SXSSFWorkbook流式API),限制单次加载行列数
3 字符编码乱码 确保数据库连接URL添加参数useUnicode=true&characterEncoding=UTF-8
4 主键冲突或唯一约束违反 插入前先查询是否存在相同记录,或启用数据库的ON DUPLICATE KEY UPDATE机制

相关问答FAQs

Q1: 如果Excel中有合并单元格怎么办?

A: 合并单元格在POI中会被视为普通单元格,但其内容仅存储于首个合并区域的锚点位置,可通过sheet.getMergeRegions()获取所有合并区域信息,手动填充缺失的值。

for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
    CellRangeAddress region = sheet.getMergedRegion(i);
    // 根据业务逻辑处理跨行合并的情况
}

Q2: 如何提高导入速度?

A: 除批处理外,还可采取以下措施:①禁用索引后再导入(适用于MyISAM引擎);②调整数据库事务隔离级别为READ_UNCOMMITTED;③多线程并行处理不同Sheet;④关闭自动提交(conn.setAutoCommit(false)),手动分阶段提交事务

0