在项目开发中往往需要使用到数据的导入和导出,导入就是从 Excel 中导入到 DB 中,而导出就是从 DB 中查询数据然后使用 POI 写到 Excel 上。
1. 存在的问题
1、 我遇到的数据量超级大,使用传统的 POI 方式来完成导入导出很明显会内存溢出,并且效率会非常低;
2、 数据量大直接使用select * from tableName
肯定不行,一下子查出来 300w 条数据肯定会很慢;
3、 300w 数据导出到 Excel 时肯定不能都写在一个 Sheet 中,这样效率会非常低;估计打开都得几分钟;
4、 300w 数据导出到 Excel 中肯定不能一行一行的导出到 Excel 中。频繁 IO 操作绝对不行;
5、 导入时 300 万数据存储到 DB 如果循环一条条插入也肯定不行;
6、导入时 300w 数据如果使用 Mybatis 的批量插入肯定不行,因为 Mybatis 的批量插入其实就是 SQL 的循环;一样很慢。
2. 解决方案
针对 1 :
其实问题所在就是内存溢出,我们只要使用对上面介绍的 POI 方式即可,主要问题就是原生的 POI 解决起来相当麻烦。
经过查阅资料翻看到阿里的一款 POI 封装工具 EasyExcel,上面问题等到解决;
针对 2:
不能一次性查询出全部数据,我们可以分批进行查询,只不过时多查询几次的问题,况且市面上分页插件很多。此问题好解决。
针对 3:
可以将 300w 条数据写到不同的 Sheet 中,每一个 Sheet 写一百万即可。
针对 4:
不能一行一行的写入到 Excel 上,我们可以将分批查询的数据分批写入到 Excel 中。
针对 5:
导入到 DB 时我们可以将 Excel 中读取的数据存储到集合中,到了一定数量,直接批量插入到 DB 中。
针对 6:
不能使用 Mybatis 的批量插入,我们可以使用 JDBC 的批量插入,配合事务来完成批量插入到 DB。即 Excel 读取分批+JDBC 分批插入+事务。
3. 具体实现
查询大量数据
在查询数据库层面,需要分批进行查询(我使用的是每次查询 20w)
插入大量数据
建立数据库连接
String url = "jdbc:mysql://localhost:3306/mydatabase";
String username = "username";
String password = "password";
Connection connection = DriverManager.getConnection(url, username, password);
// 设置connection对象为非自动提交
connection.setAutoCommit(false);
创建一个PreparedStatement对象,并指定插入语句
String insertQuery = "INSERT INTO mytable (column1, column2) VALUES (?, ?)";
PreparedStatement statement = connection.prepareStatement(insertQuery);
循环准备数据并添加到批处理中
for (int i = 0; i < data.size(); i++) {
statement.setString(1, data.get(i).getColumn1());
statement.setString(2, data.get(i).getColumn2());
statement.addBatch();
}
执行批处理操作
int[] result = statement.executeBatch();
提交事务并关闭连接
connection.commit();
connection.close();