共计 3094 个字符,预计需要花费 8 分钟才能阅读完成。
问题
线上在查比较复杂的 SQL 是,呈现以下报错:
Error querying database. Cause: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure\n\nThe last packet successfully received from the server was 10,181 milliseconds ago. The last packet sent successfully to the server was 10,239 milliseconds ago.
从报错意思上看,是数据库连贯曾经被敞开了。通过屡次试验确认,只有 SQL 执行超过 10s,就会呈现以上谬误。
起因
我的项目是
springboot
,数据库连接池用的是阿里的druid-spring-boot-starter-1.2.15
。
如上图所示:JDBC 通过 socket 对字节流进行解决,因而也会有一些根本网络操作,相似于 HttpClient 这种用于网络操作的代码库;同样的也会受到 ConnectTimeout/SocketTime
的影响。DruidDataSource
有设置以上超时的办法:
DruidDataSource dataSource = new DruidDataSource();
dataSource.setConnectTimeout(100_000);
dataSource.setSocketTimeout(100_000);
然而以后零碎并没有设置以上参数,那为什么申请超时 10s
就会报错?并且以后 druid-spring-boot-starter-1.2.15
版本并没有 socketTime&connetctTimeout
配置参数(无奈通过 spring.datasource.druid
前缀来配置)。
通过源码(DruidDatasource 类)能够看到以下内容:
public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource, MBeanRegistration {public void init() throws SQLException {
…… // 省略
try {
…… // 省略
if (this.jdbcUrl != null) {this.jdbcUrl = this.jdbcUrl.trim();
…… // 省略
initFromUrlOrProperties(); // 从 url 里解析参数}
if (connectTimeout == 0) {socketTimeout = DEFAULT_TIME_CONNECT_TIMEOUT_MILLIS; // 10_000}
if (socketTimeout == 0) {socketTimeout = DEFAULT_TIME_SOCKET_TIMEOUT_MILLIS; // 10_000}
…… // 省略
} catch (SQLException e) {…… // 省略} finally {…… // 省略}
}
}
通过以上源码能够看到,如果没有设置参数值,则会默认设置为 10s
。
持续看 initFromUrlOrProperties
办法:
public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource, MBeanRegistration {private void initFromUrlOrProperties() {
// 从 jdbc 的 url 里解析
if (jdbcUrl.startsWith("jdbc:mysql://")) {if (jdbcUrl.indexOf("connectTimeout=") != -1 || jdbcUrl.indexOf("socketTimeout=") != -1) {String[] items = jdbcUrl.split("(\\?|&)");
for (int i = 0; i < items.length; i++) {String item = items[i];
if (item.startsWith("connectTimeout=")) {String strVal = item.substring("connectTimeout=".length());
setConnectTimeout(strVal);
} else if (item.startsWith("socketTimeout=")) {String strVal = item.substring("socketTimeout=".length());
setSocketTimeout(strVal);
}
}
}
// 从配置的 connectProperties 里解析:spring.datasource.druid.connectionProperties=connectTimeout=50000;socketTimeout=50000;
Object propertyConnectTimeout = connectProperties.get("connectTimeout");
if (propertyConnectTimeout instanceof String) {setConnectTimeout((String) propertyConnectTimeout);
} else if (propertyConnectTimeout instanceof Number) {setConnectTimeout(((Number) propertyConnectTimeout).intValue());
}
Object propertySocketTimeout = connectProperties.get("socketTimeout");
if (propertySocketTimeout instanceof String) {setSocketTimeout((String) propertySocketTimeout);
} else if (propertySocketTimeout instanceof Number) {setSocketTimeout(((Number) propertySocketTimeout).intValue());
}
}
}
}
能够看到有以下两种形式来配置:
- JDBC 的 URL:
jdbc:mysql://xxxx?connectTimeout=50000&socketTimeout=50000
。 - 通过配置
spring.datasource.druid.connectionProperties
来设置:spring.datasource.druid.connectionProperties=connectTimeout=50000;socketTimeout=50000;
并且因为 initFromUrlOrProperties
办法是在 init
办法内,以及 propertyConnectTimeout
是在 URL
前面解析,能够得出优先级:connectProperties
大于 jdbcUrl
大于 set 办法
。
正文完