Mysql中使用JDBC流式查询避免数据量过大导致OOM
一、前言
java 中MySQL JDBC 封装了流式查询操作,通过设置几个参数,就可以避免一次返回数据过大导致 OOM。
二、如何使用
2.1 之前查询
public void selectData(String sqlCmd) throws SQLException {
validate(sqlCmd);
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null; try {
conn = petadataSource.getConnection();
stmt = conn.prepareStatement(sqlCmd);
rs = stmt.executeQuery(); try { while(rs.next()){ try {
System.out.println("one:" + rs.getString(1) + "two:" + rs.getString(2) + "thrid:" + rs.getString(3));
} catch (SQLException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (SQLException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
} finally {
close(stmt, rs, conn);
}
}
2.2 现在流式查询
public void selectData(String sqlCmd,) throws SQLException {
validate(sqlCmd);
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null; try {
conn = petadataSource.getConnection();
stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
rs = stmt.executeQuery(); try { while(rs.next()){ try {
System.out.println("one:" + rs.getString(1) + "two:" + rs.getString(2) + "thrid:" + rs.getString(3));
} catch (SQLException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (SQLException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
} finally {
close(stmt, rs, conn);
}
}
可知只是prepareStatement时候改变了参数,并且设置了PreparedStatement的fetchsize为Integer.MIN_VALUE。
三、 结果对比
对于同一个sqlCmd,同一批数据,使用两种方式占用内存对比如下:
- 非流式编程
- 流式编程
另外非流式方式由于是把符合条件的数据一下子全部加在到内存,并且由于数据量比较大,mysql准备数据的时间比较长,我测试情况下需要一分钟才会返回结果到内存(数据量比较大),然后才能通过数据集访问数据。
而流式方式是每次返回一个记录到内存,所以占用内存开销比较小,并且调用后会马上可以访问数据集的数据。
Mybatis中使用参考:http://www.jianshu.com/p/0339c6fe8b61
原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: Mysql中使用JDBC流式查询避免数据量过大导致OOM
不会导致io次数过多吗
客户端side游标流程
mysqlclient使用TCP链接发送请求到Server然后等待返回,Server根据条件查询数据发送到自己的发送buffer,buffer满后会fulsh并通过网络把结果发送给client接受buffer,Server端发送是阻塞模式,也就是如果客户端buffer满了则会阻塞发送
查询发起后client会创建流式resultset这个resultset里面持有该数据库连接,但是一开始不从接受buffer读取数据,然后返回该resultset给调用查询方
程序调用方得到resultset后,调用next方法,该方法内部则通过持有的数据库连接从接受buffer获取一条记录。所以说MySQL官方说的一次获取一条记录应该是说从MySQL client的接受buffer获取,而MySQL client从server一次获取多少记录与Server的发送buffer和client的接受buffer大小和TCP拥塞窗口大小有关。
所以说总的io次数应该不变,因为总数据量不变,只是非游标把全部数据发送到client所需时间更短,这是因为游标方式服务端推送数据快慢由client端调用next的频率决定。