【问题标题】:Processing on MySQL query taking too long and throwing "Communications link failure"处理 MySQL 查询耗时过长并引发“通信链接故障”
【发布时间】:2012-04-14 12:35:39
【问题描述】:

我使用 JDBC 连接发出查询:

Connection conn = null
Class.forName("com.mysql.jdbc.Driver")
conn = DriverManager.getConnection(dbHost, dbUser, dbPass)

s = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY);
s.setFetchSize(Integer.MIN_VALUE);
r = s.executeQuery (MY_SELECT_QUERY);
while(...) { 
  processResultSet(r);
}

while 运行了很长时间来处理 ResultSet。大约 1 小时后,我得到了异常:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: 通讯链路故障

从服务器成功接收到的最后一个数据包是 74 毫秒前。最后一个成功发送到服务器的数据包是 4,351,980 毫秒前。

   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:407) 
   at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1116)

   at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3082) 
   at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2968) 
   at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3516) 
   at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:931) 
   at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:1429) 
   at com.mysql.jdbc.RowDataDynamic.nextRecord(RowDataDynamic.java:416) 
   at com.mysql.jdbc.RowDataDynamic.next(RowDataDynamic.java:395) 
   at com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:7171) 
   at com.busk.indexer.AbstractIndexerClient.indexResultSet(AbstractIndexerClient.scala:34)

   at com.busk.indexer.ContinousIndexer.startIndexingLoop(ContinousIndexer.scala:18)

   at com.busk.indexer.IndexerServer$.main(IndexerServer.scala:95) 
   at com.busk.indexer.IndexerServer.main(IndexerServer.scala) 
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

   at java.lang.reflect.Method.invoke(Method.java:597)

我搜索了一下,但几乎所有错误都与连接池有关,并且使用连接超过 8 小时(默认的 wait_timeout mysql 设置)。 就我而言,我正在处理 ResultSet 并收到此错误。

【问题讨论】:

  • 是针对特定查询还是针对每个查询?你能试试像'select 1'这样的东西吗?也许在 DB 端执行查询需要太长时间?
  • 我的系统上只有这个查询(使用不同的参数)。我知道结果已经在流式传输,因为我的应用程序已经在处理 ResultSet(我通过应用程序日志查看)。该查询由 DB 定义执行,并开始发送结果,但在发送 ResultSet 项的某个时间点它停止。

标签: java mysql jdbc database-connection


【解决方案1】:

如果发生这种情况是因为结果集中有大量数据,我建议使用“LIMIT s, m”(其中 s - 开始,m - 最大记录 - 两个整数)对响应进行分页。然后在循环中处理这些数据,一次包含 1000 条记录的一部分:

boolean finished = false;
int start = 1;
int max = 1000;
do {
   r = s.executeQuery (MY_SELECT_QUERY + " LIMIT " + start + ", " + max);
   finished = // if r returned less than M records
   while(...) { 
     processResultSet(r);
   } 
   start += // number of returned records;
} while (!finished);

当然,1000 是一个任意数字,您可以四处寻找适合您查询的最佳最大尺寸。

更新:如果处理每条记录需要很长时间,则将记录存储在一个列表中,并在从数据库中获取所有数据时遍历它们。

【讨论】:

  • 数据不是那么大(它在处理 60k 行后抛出异常)。问题是每一行都需要相当长的时间来处理
  • 好的,也添加了关于这种情况的评论。
  • 在s上设置一个fetchsize可以达到同样的效果吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-24
  • 2012-06-23
  • 1970-01-01
  • 1970-01-01
  • 2018-12-24
  • 2012-06-25
相关资源
最近更新 更多