超时后,Percona连接失败

时间:2017-02-13 22:12:45

标签: mysql spring-boot connection-timeout percona

我们有数据库的多模块项目,有时我们会收到这个例外:

org.springframework.dao.DataAccessResourceFailureException: PreparedStatementCallback; SQL [SELECT data FROM table]; No operations allowed after connection closed.; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:79)
...
at java.lang.Thread.run(Thread.java:745)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
at sun.reflect.GeneratedConstructorAccessor108.newInstance(Unknown Source)
... 87 common frames omitted
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 51,072,384 milliseconds ago.  The last packet sent successfully to the server was 51,072,384 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
at sun.reflect.GeneratedConstructorAccessor89.newInstance(Unknown Source)
... 78 common frames omitted
Caused by: java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
... 83 common frames omitted
谷歌建议,可能是因为数据库在wait_timeout变量中没有及时指定查询时关闭连接。 所以我以这种方式重现了这种情况:

使用Percona服务器5.7.16,SpringBoot 1.3.3

在mysql中设置超时以演示问题(在生产中设置默认值为8小时):

SET GLOBAL interactive_timeout = 15;
SET GLOBAL wait_timeout = 15;

在springboot属性中为mysql设置heartbeat:

spring.datasource.validationQuery=SELECT 1
spring.datasource.testWhileIdle = true

运行测试:

@Test
@DatabaseSetup("/....xml")
public void test() throws Exception {
    mockMvc
        .perform(get("/request_that_fetches_data_from_db"))
        .andExpect(status().isOk());

    sleep(1000 * 60);
    mockMvc
         .perform(get("/request_that_fetches_data_from_db"))
        .andExpect(status().isOk());

}

结果是:

java.sql.SQLException: Could not retrieve transation read-only status server

at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
...

Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 40 414 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
...
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2957)
... 46 more
我看了一下mysql的一般日志。每10秒有一次查询SELECT 1次传递,但是在收到业务查询之后,直接接收命令quit。测试期间错误日志为空。

有什么问题以及如何在不增加wait_timeout的情况下解决此问题?

P.S。jdbc:mysql://url?autoReconnect=true也不起作用。

0 个答案:

没有答案