EasyExcel 是阿里巴巴开源的一个用于处理 Excel 文件的 Java 库,其核心优势在于轻量、高效以及对大数据量的支持。在实际项目中,我们经常需要将 EasyExcel 与数据库交互结合使用,比如从数据库读取数据并写入 Excel 文件,或者解析 Excel 文件后将数据插入到数据库中。
下面我们将详细介绍如何实现 EasyExcel 与数据库交互的最佳实践,包括数据读取、写入以及性能优化等关键环节。
在开始之前,请确保你的项目已经引入了 EasyExcel 和数据库驱动的相关依赖。例如,Maven 配置如下:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
此外,还需要配置好数据库连接池(如 HikariCP 或 Druid)以保证数据库操作的稳定性。
从数据库中查询数据,并将其逐行写入 Excel 文件。为了提高效率,可以分批读取数据并使用 EasyExcel 的 write
方法进行批量写入。
定义实体类:创建一个与 Excel 表头对应的实体类。
public class User {
private String name;
private Integer age;
// Getter and Setter
}
编写数据库查询方法: 使用 JDBC 或 MyBatis 查询数据,并分批加载结果集。
public List<User> getUsersByBatch(int offset, int limit) {
String sql = "SELECT name, age FROM user LIMIT ? OFFSET ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, limit);
pstmt.setInt(2, offset);
ResultSet rs = pstmt.executeQuery();
List<User> users = new ArrayList<>();
while (rs.next()) {
User user = new User();
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
users.add(user);
}
return users;
} catch (SQLException e) {
throw new RuntimeException("Database query error", e);
}
}
调用 EasyExcel 写入数据: 分批读取数据库数据并写入 Excel 文件。
public void writeUsersToExcel(String fileName) {
try (OutputStream out = new FileOutputStream(fileName)) {
WriteWorkbookHolder workbookHolder = EasyExcel.write(out, User.class).build();
WriteSheet sheet = EasyExcel.writerSheet("用户数据").build();
int batchSize = 1000; // 每次读取的数据量
int offset = 0;
List<User> users;
do {
users = getUsersByBatch(offset, batchSize);
if (users != null && !users.isEmpty()) {
EasyExcel.write(out, User.class)
.sheet(sheet.getSheetNo(), sheet.getSheetName())
.doWrite(users);
}
offset += batchSize;
} while (!users.isEmpty());
} catch (IOException e) {
throw new RuntimeException("Excel write error", e);
}
}
通过 EasyExcel 解析 Excel 文件,将解析后的数据插入到数据库中。为了避免一次性加载大量数据导致内存溢出,可以采用分批插入的方式。
定义监听器:创建一个继承自 AbstractAnalysisEventListener
的监听器类,用于处理每一批解析完成的数据。
public class UserListener extends AbstractAnalysisEventListener<User> {
private static final int BATCH_COUNT = 1000;
private List<User> userList = new ArrayList<>(BATCH_COUNT);
private DataSource dataSource;
public UserListener(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void invoke(User data, AnalysisContext context) {
userList.add(data);
if (userList.size() >= BATCH_COUNT) {
saveData();
userList.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
if (!userList.isEmpty()) {
saveData();
}
}
private void saveData() {
String sql = "INSERT INTO user (name, age) VALUES (?, ?)";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
for (User user : userList) {
pstmt.setString(1, user.getName());
pstmt.setInt(2, user.getAge());
pstmt.addBatch();
}
pstmt.executeBatch();
} catch (SQLException e) {
throw new RuntimeException("Database insert error", e);
}
}
}
调用 EasyExcel 解析文件:
public void readExcelAndSaveToDB(String fileName, DataSource dataSource) {
UserListener listener = new UserListener(dataSource);
EasyExcel.read(fileName, User.class, listener).sheet().doRead();
}
以下是数据写入和读取的整体流程图:
graph TD A[开始] --> B{操作类型} B --写入--> C[从数据库分批读取数据] C --> D[使用EasyExcel写入Excel] D --> E[完成写入] B --读取--> F[使用EasyExcel解析Excel] F --> G[分批插入数据库] G --> H[完成读取]