Странное исключение JDBC executeQuery
У меня есть следующий код:
public Object RunQuery(String query) throws Exception{
System.out.println("Trying to run query");
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
System.out.println("Got Statement");
rs = stmt.executeQuery(query);
System.out.println("Query executed");
...
} catch (SQLException ex) {
// handle any errors
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
catch (Exception ex) {
System.out.println("Exception: " + ex.getMessage());
}
finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException sqlEx) {
} // ignore
rs = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlEx) {
} // ignore
stmt = null;
}
return ret;
}
}
Который прекрасно работает при запуске
query = "SELECT * FROM smalltable"
Но терпит неудачу на
query = "SELECT * FROM bigtable"
который имеет около 200 тысяч записей. Отладчик элегантно игнорирует блоки catch и идет прямо в блок finally; NetBeans дал мне этот кадр стека, когда я добавил stmt.executeQuery(запрос) в список наблюдения:
>Exception occurred in target VM: Communications link failure Last packet sent to the server was 0 ms ago.
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure Last packet sent to the server was 0 ms ago.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1074)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3009)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2895)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3438)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1951)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2101)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2548)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2477)
at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1422)
at RunQuery
Caused by: java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:157)
at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:188)
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2452)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2962)
... 9 more
Как я могу делать большие запросы в этой структуре?
РЕДАКТИРОВАТЬ: я использую J-коннектор и MySQL сервер 5.1; строка подключения
jdbc:mysql://localhost?user=root&password=password
Да, я знаю, что select * - это плохая практика, но, как вы можете видеть, я только начал, и это более или менее второй тест, который я делаю
3 ответа
Единственное, о чем я могу подумать, это может вызвать разницу, это какой-то тайм-аут на уровне сети, и выходные данные Netbeans, безусловно, будут указывать в этом направлении. Какую строку соединения JDBC вы используете; возможно есть параметр тайм-аута, который может быть увеличен?
Возможно, также стоит подключить анализатор сетевых пакетов, если проблема не исчезнет, и посмотрите, что происходит на этом уровне. Поиграйте "определите разницу" с короткими и длинными запросами, и вы можете получить хорошее представление о том, что делает один неудачным, а другой - успешным.
(В общем select *
это плохая идея просто из-за всех дополнительных данных, которые она возвращает без необходимости. В этом случае выбор всех столбцов из всех строк большой таблицы, очевидно, создает проблемы с подключением по сравнению с выбором из таблицы меньшего размера. Я знаю, что в этом случае ваш вопрос по-прежнему актуален, так как иногда вам может понадобиться это сделать, и помимо выбора подмножества еще большей таблицы, вероятно, будет сделано то же самое, но я просто указываю на это в качестве общего руководства в Если вы использовали это в качестве ярлыка для производства.)
Я сразу подумал, что может быть проблема с памятью при получении всех этих данных. Я не знаю, как MySQL настроен для этой цели, но вы можете попробовать установить размер выборки в ResultSet или ограничить размер ResultSet, выбрав меньшее количество столбцов. Возможно, драйвер JDBC пытается извлечь всю таблицу за одну операцию.
Как примечание, пожалуйста, пожалуйста, никогда не делайте stmt.executeQuery (запрос). Всегда используйте PreparedStatement и привязывайте параметры запроса. В вашем примере нет параметров, но это очень важно для целей безопасности. Никогда не используйте SQL с параметрами, которые являются "литералами" (исключение составляют случаи, когда ваши литералы являются доверенными строками, такими как константы из вашего кода, или не строковыми типами, такими как числа, которые вы уже проанализировали).
Если он пропускает непосредственно к окончанию, является ли "исключение", которое выбрасывается внутри другого кода, на самом деле потомком ошибки? Это позволит полностью избежать вашего улова.
Вы могли получить OutOfMemoryError, а затем получить сетевое исключение, потому что OOME закрыл некоторые вещи?