作者:じ☆ve宝贝
发布时间:2018-01-08T17:13:44
MySQL 导出大量数据时,如果不做分页限制会直接提示java.lang.OutOfMemoryError: Java heap space,如果使用limit加载全部数据的话,limit在超过一定数据量后性能大幅度下降,不能满足我们的需求。查找文档后找到MySQL的JDBC中fetchSize参数可以解决该问题。
** setFetchSize (int rows) ** :为 JDBC 驱动程序提供一个提示,它提示此 Statement 生成的 ResultSet 对象需要更多行时应该从数据库获取的行数。
** MysqlExportData.java **
package cn.studyjava;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import cn.studyjava.common.Const;
/**
* MySQL 导出大批量数据(取回数据量为 6504622 行!总计用时:1270/s, 平均每6万用时12/s)
* @author zsljava 2018年1月8日 下午3:44:18
* @since 1.0.0
*/
public class MysqlExportData {
public static long exportData(String sql) {
String url = "jdbc:mysql://localhost:3306/data?user=root&password=XXXX";
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
long allStart = System.currentTimeMillis();
long count = 0;
Connection con = null;
PreparedStatement ps = null;
// Statement st = null;
ResultSet rs = null;
try {
con = DriverManager.getConnection(url);
ps = (PreparedStatement) con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(Integer.MIN_VALUE);
ps.setFetchDirection(ResultSet.FETCH_REVERSE);
// 默认3600 s 的query Timeout(查询超时后自动关闭,因为我们需要流链接,因此不能短时间关闭)
ps.setQueryTimeout(Const.SOCKET_TIMEOUT_INSECOND);
rs = ps.executeQuery();
System.out.println("开始执行");
long oneStart = System.currentTimeMillis();
while (rs.next()) {
// 此处处理业务逻辑
count++;
if (count % 60000 == 0) {
long end = System.currentTimeMillis();
System.out.println(" 写入到第 " + (count / 60000) + " 个文件中, 用时:" + ((end - oneStart) / 1000) + "/s");
oneStart = end;
}
}
long end = System.currentTimeMillis();
System.out.println("取回数据量为 " + count + " 行!总计用时:"+((end - allStart)/1000)+"/s");
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (ps != null) {
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return count;
}
public static void main(String[] args) throws InterruptedException {
String sql = "select * from company ";
exportData(sql);
}
}
** Const.java **
package cn.studyjava.common;
/**
*
* @author zsljava 2017年12月12日 下午2:22:18
* @since 1.0.0
*/
public class Const {
public static final int SOCKET_TIMEOUT_INSECOND = 172800;
}
** maven pom.xml **
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.43</version>
</dependency>
可以通过MySQL jdbc的fetchSize参数,解决MySQL一次性查询数据量过大时导致内存溢出的问题。 欢迎大家讨论交流