Java C3P0+;MySQL:读取通信数据包时出错

Java C3P0+;MySQL:读取通信数据包时出错,java,mysql,c3p0,Java,Mysql,C3p0,许多人遇到的错误与以下消息有关: [Warning] Aborted connection 38 to db: 'database_name' user: 'root' host: 'localhost' (Got an error reading communication packets) 可以在MySQL日志中找到。在我的例子中,通过java客户机使用驱动程序com.mysql.jdbc.driver和众所周知的C3P0池本地访问数据库。我的MySQL服务器配置为接受相当多的连接,最大

许多人遇到的错误与以下消息有关:

[Warning] Aborted connection 38 to db: 'database_name' user: 
'root' host: 'localhost' (Got an error reading communication packets)
可以在MySQL日志中找到。在我的例子中,通过java客户机使用驱动程序
com.mysql.jdbc.driver
和众所周知的C3P0池本地访问数据库。我的MySQL服务器配置为接受相当多的连接,最大允许数据包值设置为64M。以下是my.cnf文件(MySQL配置)的摘录:

我的数据库中的表
User
具有以下简单结构:

CREATE TABLE `User` (
  `uid` varchar(255) COLLATE utf8_bin NOT NULL,
  `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `mail` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `password` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `maxParallelTasks` tinyint(4) NOT NULL DEFAULT '10',
  `maxModels` int(11) NOT NULL DEFAULT '2000',
  `maxBibTeX` int(11) NOT NULL DEFAULT '2000',
  PRIMARY KEY (`uid`) USING BTREE,
  UNIQUE KEY `mail` (`mail`) USING BTREE,
  KEY `uid` (`uid`) USING BTREE,
  KEY `index_user_name` (`name`) USING BTREE,
  KEY `index_user_mail` (`mail`) USING BTREE,
  KEY `index_user_maxModels` (`maxModels`) USING BTREE,
  KEY `index_user_maxBibTeX` (`maxBibTeX`) USING BTREE,
  KEY `index_user_maxParallelTasks` (`maxParallelTasks`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
当我使用mysql客户端在该表中插入一个值时(即
mysql-u root-p
),我在日志中没有收到任何警告。然而,当尝试相同的Java端时,上述警告会多次出现在日志中!因此,在Java方面,我的连接来自C3P0连接池,配置如下:

datasource = new ComboPooledDataSource();
datasource.setJdbcUrl(connectURI);
datasource.setMaxPoolSize(1000);
datasource.setMinPoolSize(20);
datasource.setInitialPoolSize(50);
datasource.setNumHelperThreads(6);
datasource.setTestConnectionOnCheckin(true);
datasource.setTestConnectionOnCheckout(true);
声明首先编写:

PreparedStatement ps = connection.prepareStatement(getSql());
然后参数化:

ps.setString(1, user.getUid());
ps.setString(2, user.getName());
ps.setString(3, user.getMail());
ps.setString(4, user.getHashedPass());
然后执行:

int update = ps.executeUpdate();
然后关闭准备好的语句:

ps.close();
并且SQL连接已关闭:

if (connection != null) {
            try {
                if (!connection.isClosed()) {
                    connection.close();
                }
            } catch (SQLException ex) {
                throw new DbException(ex);
            }
}
整个程序(在我看来)似乎是合法的。根据位于的MySQL手册,此警告可能意味着:

客户端程序没有调用 退出前关闭mysql_()

或者:

客户端程序在年突然结束 数据传输的中间部分

在我的应用程序中,我使用C3P0使用200多个并行线程在该数据库中写入和读取数据,并且在检查数据是否实际正常传输到数据库和从数据库中检索时,我没有内存泄漏。还有其他人有类似的经历吗

最后,我将介绍我的MySQL版本以及可能对故障排除有用的其他信息:

mysql> show variables like "%version%";
+-------------------------+-------------------+
| Variable_name           | Value             |
+-------------------------+-------------------+
| protocol_version        | 10                | 
| version                 | 5.1.37-1ubuntu5.5 | 
| version_comment         | (Ubuntu)          | 
| version_compile_machine | x86_64            | 
| version_compile_os      | debian-linux-gnu  | 
+-------------------------+-------------------+


好吧,很高兴看到一个问题,它包含了正确数量的信息,可以提示系统可能遇到问题的地方。以下是我要检查的内容:

  • 在关闭
    连接之前,尝试关闭
    PreparedStatement
    对象,并验证这是否解决了问题。这听起来可能不必要,但对于某些JDBC驱动程序来说是必需的,最明显的是Oracle(也可能是MySQL)。基本原理是,
    连接
    对象并不是真正关闭的,特别是当像
    结果集
    语句
    对象这样的派生对象没有首先关闭时(按照所提到的顺序)。部分原因在于JDBC驱动程序的编写方式
  • 验证所涉及的机器是否能够实际处理您希望它们处理的负载。如果底层网络基础设施无法处理指定数量的连接,则很可能会断开连接。如果第一条建议没有帮助,您可能希望查看wireshark转储并从中得出推论
  • 使用
    debugUnreturnedConnectionStackTraces
    标志检测任何连接池泄漏。这还要求unreturnedConnectionTimeout为正值。该标志确保为应用程序不将连接返回池的情况提供堆栈跟踪。堆栈跟踪将指示最初保留连接的代码点

    • 试图深入探究此警告的原因

      首先,我注意到我在日志文件中收到的警告消息数量等于或非常接近
      datasource.setMinPoolSize(int)指定的最小池大小而为了测试而设置的初始池大小每次都等于最小大小

      此外,通过使用调试器和一步一步地执行语句,我有时间观察到,一旦单元测试完成,警告就会被记录下来。这些事实使我得出结论,C3P0汇集的连接在被丢弃之前实际上并没有关闭。需要的是,一旦不再使用数据源,调用方法
      com,就关闭数据源。​麦克亨格。​v2。​c3p0。​impl。​AbstractPoolBackedDataSource#close()
      。当然,只有在单元测试结束时才这样做是有意义的,因此在我的情况下,修订如下:

      @AfterClass
      public static void tearDownClass() throws Exception {
        // Close the pool 
        DataSourceFactory.getInstance().close();
      }
      
      在我的应用程序中,我添加了一个shutdownhook,以便数据源在执行停止之前关闭。在此之前,池连接保持不变,驱动程序必须关闭它们,从而在MySQL日志中引起警告。这解决了所有INSERT操作的问题,但不幸的是,并不是针对SELECT操作。请注意,我关闭了所有结果集、语句、准备好的语句和连接,并使用(静态分析工具)检查了源代码。一个变通方法让我怀疑C3P0又出了问题,但我不能确定。因此,以下内容将使警告消失

      @AfterClass
      public static void tearDownClass() throws Exception {
        Thread.sleep(100000); // wait for 100 secs
        DataSourceFactory.getInstance().close();
      }
      

      请注意,在100秒结束(数据源工厂关闭)之前,日志中不会出现任何警告!因此,是
      datasource.close()
      导致它们…

      在连接之前关闭准备好的语句。然而,这两个都关闭了。关于负载,我运行了一个只涉及一个INSERT语句的单元测试,因此这里的情况不是超出服务器可以处理的连接数。@Pantelis Sopasakis,连接池的最小大小设置为50。我不确定你的单元测试是否真的在检查这个。此外,我还更新了答案,以反映调试标志的使用,该标志可能有助于检测连接池使用过程中固有的连接池泄漏的可能性。非常感谢您的帮助!问题现在解决了:-)我现在发布答案。
      Java version: 1.6.0_22, (build 1.6.0_22-b04)
      
      @AfterClass
      public static void tearDownClass() throws Exception {
        // Close the pool 
        DataSourceFactory.getInstance().close();
      }
      
      @AfterClass
      public static void tearDownClass() throws Exception {
        Thread.sleep(100000); // wait for 100 secs
        DataSourceFactory.getInstance().close();
      }