本文旨在深入探讨如何通过Apache POI库实现这一导入过程,并针对性能瓶颈提出有效的优化策略,确保数据导入的高效性与稳定性
一、引言 Apache POI是一个强大的Java库,它能够读写Microsoft Office文档,包括Excel(XLS和XLSX格式)
在处理大量数据时,直接将Excel中的数据通过POI读取并插入MySQL数据库,可能会遇到性能瓶颈,尤其是当数据量达到百万级别时
因此,本文将分为两部分:基础实现与优化策略
二、基础实现:POI读取Excel并导入MySQL 2.1 环境准备 在开始之前,确保你的开发环境中已经包含了必要的依赖项: - Apache POI库(包括poi, poi-ooxml, poi-ooxml-schemas等) - MySQL JDBC驱动 - 一个支持Java开发的IDE(如IntelliJ IDEA或Eclipse) 2.2 POI读取Excel文件 使用POI读取Excel文件的基本步骤如下: java import org.apache.poi.ss.usermodel.; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileInputStream; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class ExcelToMySQL{ public static void main(String【】 args){ String excelFilePath = path/to/your/excel/file.xlsx; String jdbcUrl = jdbc:mysql://localhost:3306/yourdatabase; String username = yourusername; String password = yourpassword; try(FileInputStream fis = new FileInputStream(excelFilePath); Workbook workbook = new XSSFWorkbook(fis); Connection conn = DriverManager.getConnection(jdbcUrl, username, password)){ Sheet sheet = workbook.getSheetAt(0); for(Row row : sheet){ if(row.getRowNum() ==0) continue; //跳过标题行 //假设Excel中有三列:id, name, age int id =(int) row.getCell(0).getNumericCellValue(); String name = row.getCell(1).getStringCellValue(); int age =(int) row.getCell(2).getNumericCellValue(); String sql = INSERT INTO yourtable(id, name, age) VALUES(?, ?, ?); try(PreparedStatement pstmt = conn.prepareStatement(sql)){ pstmt.setInt(1, id); pstmt.setString(2, name); pstmt.setInt(3, age); pstmt.executeUpdate(); } } System.out.println(Data imported successfully!); } catch(IOException | SQLException e){ e.printStackTrace(); } } } 上述代码展示了如何使用POI读取Excel文件,并通过JDBC将每行数据插入MySQL数据库
然而,这种方法在处理百万级数据时效率极低,因为每次插入操作都会开启和关闭数据库连接,造成大量开销
三、优化策略 为了提升数据导入效率,我们需要从以下几个方面进行优化: 3.1 批量插入 使用JDBC的批处理功能可以显著减少数据库交互次数,从而提高性能
修改代码如下: java try(Connection conn = DriverManager.getConnection(jdbcUrl, username, password); PreparedStatement pstmt = conn.prepareStatement(INSERT INTO yourtable(id, name, age) VALUES(?, ?,?))){ conn.setAutoCommit(false); // 关闭自动提交 Sheet sheet = workbook.getSheetAt(0); for(Row row : sheet){ if(row.getRowNum() ==0) continue; //跳过标题行 int id =(int) row.getCell(0).getNumericCellValue(); String name = row.getCell(1).getStringCellValue(); int age =(int) row.getCell(2).getNumericCellValue(); pstmt.setInt(1, id); pstmt.setString(2, name); pstmt.setInt(3, age); pstmt.addBatch(); //添加到批处理 if(++batchCount % BATCH_SIZE ==0){ // 每BATCH_SIZE条执行一次批处理 pstmt.executeBatch(); conn.commit(); } } pstmt.executeBatch(); // 执行剩余批处理 conn.commit(); //提交事务 conn.setAutoCommit(true); // 恢复自动提交 } catch(SQLException e){ e.printStackTrace(); if(conn!= null) try{ conn.rollback();} catch(SQLException ex){ ex.printStackTrace();} } 其中,`BATCH_SIZE`是一个自定义的常量,表示每次批处理的大小,通常设为几百到几千不等,具体数值需根据实际情况调整
3.2 使用内存数据库或临时文件 对于极端大数据量,可以考虑先将Excel数据读取到内存数据库(如H2)或写入临时文件(如CSV),然后再批量导入MySQL
这种方法可以减少Java堆内存的压力,同时利用数据库自身的批量导入工具(如MySQL的`LOAD DATA INFILE`)进一步提高效率
3.3 调整MySQL配置 -增加innodb_buffer_pool_size:对于InnoDB存储引擎,增加缓冲区池大小可以加快数据读写速度
-禁用唯一性检查和外键约束:在数据导入期间暂时禁用这些约束可以加速插入过程,但务必在导入完成后重新启用
-使用事务:确保整个导入过程在一个事务中完成,可以减少日志写入次数,提高性能
3.4 并行处理 如果