奇怪的 JDBC 执行查询异常
我有以下代码:
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"
但在大约有 200K 记录 。 调试器优雅地忽略catch块并直接进入finally块; 当我将 stmt.executeQuery(query) 添加到监视列表时,NetBeans 给了我这个堆栈框架:
>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
Yes,我知道 select * 是一个不好的做法,但正如你所看到的,我刚刚开始,这或多或少是我正在进行的第二个测试
I have the following code:
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;
}
}
Which works perfectly fine when running
query = "SELECT * FROM smalltable"
But fails on
query = "SELECT * FROM bigtable"
which has about 200K records.
The debugger elegantly ignores the catch blocks and goes straight into the finally block; NetBeans gave me this stack frame when I added stmt.executeQuery(query) to the watch list:
>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
How can I do large queries in this framework?
EDIT: I'm using J connector and mysql server 5.1; the connection string is
jdbc:mysql://localhost?user=root&password=password
Yes, I know that select * is a bad practice, but as you can see I just begun and this is more or less the second test I'm doing
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我能想到的唯一会导致差异的是某种网络级超时,并且 Netbeans 输出肯定会指向这个方向。 您正在使用的 JDBC 连接字符串是什么; 也许有一个可以提高的超时参数?
如果问题仍然存在,也可能值得插入网络数据包嗅探器,看看该级别的通信情况如何。 通过短查询和长查询来玩“找出差异”游戏,您可能会很好地了解是什么导致一个查询失败而另一个查询成功。
(一般来说,
select *
是一个坏主意,因为它会带来不必要的额外数据。在这种情况下,从大表中的所有行中选择所有列显然会给连接带来麻烦与从较小的表中进行选择相比,我知道在这种情况下您的问题仍然有效,因为有时您可能需要这样做,而且除了选择更大的表的子集可能会做同样的事情,但我只是指出这一点作为一般准则,以防您在生产中使用它作为快捷方式。)The only thing I can think of that would cause the difference is some kind of network-level timeout, and the Netbeans output would certainly point in this direction to. What is the JDBC connection string you are using; perhaps there's a timeout parameter that can be bumped up?
It might also be worth plugging in a network packet sniffer if the problem persists and see what communications are like at that level. Play "spot the difference" with the short and long queries and you might get a good idea of what's making one fail where the other succeeds.
(In general
select *
is a bad idea simply because of all the extra data it brings back unnecessarily. In this case, selecting all the columns from all the rows in the big table is obviously giving the connection trouble compared to selecting from the smaller table. I know that in this case your question is still valid as sometimes you may need to do this, and besides selecting a subset of an even larger table would probably do the same thing, but I'm just pointing this out as a general guideline in case you were using this in production as a shortcut.)我立即想到的是,获取所有这些数据可能会出现内存问题。 我不知道 MySQL 是如何为此目的设置的,但您可能想尝试在 ResultSet 中设置获取大小或通过选择更少的列来限制 ResultSet 大小。 JDBC 驱动程序可能会尝试在一次操作中获取整个表。
作为旁注,请永远不要执行 stmt.executeQuery(query)。 始终使用PreparedStatement 并绑定查询参数。 在您的示例中没有参数,但这是一种对于安全目的至关重要的做法。 切勿将 SQL 与“文字”参数一起使用(例外情况是当您的文字是受信任的字符串(例如代码中的常量)或非字符串类型(例如您已解析的数字)时。
My immediate thought is that there could be a memory issue with fetching all that data. I don't know how MySQL is set up for this purpose, but you might want to try setting the fetch size in the ResultSet or limiting the ResultSet size by selecting fewer columns. It's possible that the JDBC driver is trying to fetch the entire table in one operation.
As a side note, please please please never do stmt.executeQuery(query). Always use a PreparedStatement and bind your query parameters. In your example there are no parameters, but this is a practice that's critical for security purposes. Never use SQL with parameters that are 'literals' (the exception is when your literals are trusted strings such as constants from your code or non string types such as numbers which you've already parsed).
如果它直接跳到最后,那么在其他代码中抛出的“异常”实际上是 Error 的后代吗? 这将完全避免你的捕获。
你可能会遇到 OutOfMemoryError,然后因为 OOME 关闭了一些东西而出现网络异常?
If it is skipping directly to the finally, is the "exception" thats being thrown inside the other code actually a descendant of Error? That would avoid your catch entirely.
you might have gotten an OutOfMemoryError, then gotten the network exception because the OOME closed some stuff?