Streaming large result sets with MySQL

java, mysql, spring, streaming

Solution

Don't close your `ResultSet`s twice.

Apparently, when closing a `Statement` it attempts to close the corresponding `ResultSet`, as you can see in these two lines from the stack trace:

DelegatingResultSet.close() line: 152 DelegatingPreparedStatement(DelegatingStatement).close() line: 163

I had thought the hang was in `ResultSet.close()` but it was actually in `Statement.close()` which calls `ResultSet.close()`. Since the `ResultSet` was already closed, it just hung.

We've replaced all `ResultSet.close()` with `results.getStatement().close()` and removed all `Statement.close()`s, and the problem is now solved.

Problem

I'm developing a spring application that uses large MySQL tables. When loading large tables, I get an `OutOfMemoryException`, since the driver tries to load the entire table into application memory. I tried using ``` statement.setFetchSize(Integer.MIN_VALUE); ``` but then every ResultSet I open hangs on `close()`; looking online I found that that happens because it tries loading any unread rows before closing the ResultSet, but that is not the case since I do this: ``` ResultSet existingRecords = getTableData(tablename); try { while (existingRecords.next()) { // ... } } finally { existingRecords.close(); // this line is hanging, and there was no exception in the try clause } ``` The hangs happen for small tables (3 rows) as well, and if I don't close the RecordSet (which happened in one method) then `connection.close()` hangs. Stack trace of the hang: SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) line: not available [native method] SocketInputStream.read(byte[], int, int) line: 129 ReadAheadInputStream.fill(int) line: 113 ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(byte[], int, int) line: 160 ReadAheadInputStream.read(byte[], int, int) line: 188 MysqlIO.readFully(InputStream, byte[], int, int) line: 2428 MysqlIO.reuseAndReadPacket(Buffer, int) line: 2882 MysqlIO.reuseAndReadPacket(Buffer) line: 2871 MysqlIO.checkErrorPacket(int) line: 3414 MysqlIO.checkErrorPacket() line: 910 MysqlIO.nextRow(Field[], int, boolean, int, boolean, boolean, boolean, Buffer) line: 1405 RowDataDynamic.nextRecord() line: 413 RowDataDynamic.next() line: 392 RowDataDynamic.close() line: 170 JDBC4ResultSet(ResultSetImpl).realClose(boolean) line: 7473 JDBC4ResultSet(ResultSetImpl).close() line: 881 DelegatingResultSet.close() line: 152 DelegatingResultSet.close() line: 152 DelegatingPreparedStatement(DelegatingStatement).close() line: 163 (This is my class) Database.close() line: 84

Original source

Related problems