項(xiàng)目上線一段時(shí)間后,多個(gè)環(huán)境經(jīng)常出現(xiàn)com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure錯(cuò)誤,堆棧信息如下:
The last packet successfully received from the server was 10,003 milliseconds ago. The last packet sent successfully to the server was 10,003 milliseconds ago.
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
at com.mysql.cj.jdbc.StatementImpl.executeQuery(StatementImpl.java:1200)
at com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker.isValidConnection(MySqlValidConnectionChecker.java:140)
at com.alibaba.druid.pool.DruidAbstractDataSource.validateConnection(DruidAbstractDataSource.java:1440)
at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1812)
at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2877)
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
The last packet successfully received from the server was 10,003 milliseconds ago. The last packet sent successfully to the server was 10,003 milliseconds ago.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151)
at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:167)
at com.mysql.cj.protocol.a.NativeProtocol.readMessage(NativeProtocol.java:538)
at com.mysql.cj.protocol.a.NativeProtocol.checkErrorMessage(NativeProtocol.java:702)
at com.mysql.cj.protocol.a.NativeProtocol.sendCommand(NativeProtocol.java:641)
at com.mysql.cj.protocol.a.NativeProtocol.sendQueryPacket(NativeProtocol.java:940)
at com.mysql.cj.protocol.a.NativeProtocol.sendQueryString(NativeProtocol.java:886)
at com.mysql.cj.NativeSession.execSQL(NativeSession.java:1073)
at com.mysql.cj.jdbc.StatementImpl.executeQuery(StatementImpl.java:1168)
… 4 common frames omitted
Caused by: java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:475)
at sun.security.ssl.SSLSocketInputRecord.readHeader(SSLSocketInputRecord.java:469)
at sun.security.ssl.SSLSocketInputRecord.bytesInCompletePacket(SSLSocketInputRecord.java:69)
at sun.security.ssl.SSLSocketImpl.readApplicationRecord(SSLSocketImpl.java:1228)
at sun.security.ssl.SSLSocketImpl.access
300
(
S
S
L
S
o
c
k
e
t
I
m
p
l
.
j
a
v
a
:
75
)
a
t
s
u
n
.
s
e
c
u
r
i
t
y
.
s
s
l
.
S
S
L
S
o
c
k
e
t
I
m
p
l
300(SSLSocketImpl.java:75) at sun.security.ssl.SSLSocketImpl
300(SSLSocketImpl.java:75)atsun.security.ssl.SSLSocketImplAppInputStream.read(SSLSocketImpl.java:915)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at com.mysql.cj.protocol.FullReadInputStream.readFully(FullReadInputStream.java:64)
at com.mysql.cj.protocol.a.SimplePacketReader.readHeader(SimplePacketReader.java:63)
at com.mysql.cj.protocol.a.SimplePacketReader.readHeader(SimplePacketReader.java:45)
at com.mysql.cj.protocol.a.TimeTrackingPacketReader.readHeader(TimeTrackingPacketReader.java:52)
at com.mysql.cj.protocol.a.TimeTrackingPacketReader.readHeader(TimeTrackingPacketReader.java:41)
at com.mysql.cj.protocol.a.MultiPacketReader.readHeader(MultiPacketReader.java:54)
at com.mysql.cj.protocol.a.MultiPacketReader.readHeader(MultiPacketReader.java:44)
at com.mysql.cj.protocol.a.NativeProtocol.readMessage(NativeProtocol.java:532)
… 10 common frames omitted
經(jīng)過多次排查和測試,終于排查到了原因。
出現(xiàn)問題的原因是因?yàn)槲覀兊捻?xiàng)目需要?jiǎng)討B(tài)配置數(shù)據(jù)源,程序中根據(jù)需要即時(shí)動(dòng)態(tài)創(chuàng)建DruidDataSource,沒有設(shè)置SocketTimeout和ConnectTimeout參數(shù),默認(rèn)值都是0,有文章說:connectTimeout的默認(rèn)值為0,表示驅(qū)動(dòng)層面不設(shè)置超時(shí)時(shí)間,但這并不意味著不會(huì)超時(shí),此時(shí)將由操作系統(tǒng)來決定超時(shí)時(shí)間。實(shí)際經(jīng)過測試,當(dāng)SocketTimeout和ConnectTimeout為默認(rèn)值0時(shí),兩個(gè)超時(shí)時(shí)間可能都為10秒。
測試代碼:
public static void main(String[] args) throws Exception {
//創(chuàng)建數(shù)據(jù)源
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=GMT%2B8");
druidDataSource.setUsername("admin");
druidDataSource.setPassword("admin");
druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
String querySql = "SELECT sleep(11)"; //執(zhí)行語句,該行語句的執(zhí)行時(shí)間≥11秒
druidDataSource.setConnectionErrorRetryAttempts(3); //失敗后重連次數(shù)
druidDataSource.setBreakAfterAcquireFailure(true);
druidDataSource.setMaxWait(30 * 1000); //保持的最長時(shí)間
// 以下配置自動(dòng)檢測鏈接的可用性
druidDataSource.setTestWhileIdle(true); //明確指定檢測空閑鏈接是否可用
druidDataSource.setValidationQuery("select 1"); //執(zhí)行該SQL來檢測空閑鏈接,如果不配置,實(shí)際不會(huì)執(zhí)行檢測
//如果鏈接空閑時(shí)長超過60秒則執(zhí)行檢測,周而復(fù)始。如果該時(shí)長少于MySQL數(shù)據(jù)變量:wait_timeout 會(huì)出現(xiàn)鏈接不可用的情況。
druidDataSource.setTimeBetweenEvictionRunsMillis(60 * 1000);
druidDataSource.setSocketTimeout(20 * 1000);//超時(shí)時(shí)長:20秒,該值要大于執(zhí)行語句的執(zhí)行時(shí)間
druidDataSource.setConnectTimeout(20 * 1000);//超時(shí)時(shí)長:20秒,該值要大于執(zhí)行語句的執(zhí)行時(shí)間
List<Map<String, Object>> result = JdbcUtils.executeQuery(druidDataSource, querySql, Lists.newArrayList());
System.out.println(JSONUtilExt.toJson(result));
}
請注意測試代碼中的這兩行代碼:
druidDataSource.setSocketTimeout(20 * 1000);
druidDataSource.setConnectTimeout(20 * 1000);
當(dāng)我將這兩行代碼中的任意一行代碼注釋掉或兩行代碼都注釋掉時(shí),都會(huì)出現(xiàn)文章開始的錯(cuò)誤,且錯(cuò)誤日志相同。文章來源:http://www.zghlxwxcb.cn/news/detail-722525.html
分析到此,基本可以確定,程序里出現(xiàn)上面錯(cuò)誤就是因?yàn)镾ocketTimeout和ConnectTimeout沒有設(shè)置,導(dǎo)致操作系統(tǒng)里實(shí)際默認(rèn)的時(shí)間是10秒,而因?yàn)轫?xiàng)目已經(jīng)上線一段時(shí)間,個(gè)別表里數(shù)據(jù)量比較大,所以在執(zhí)行語句時(shí)偶爾會(huì)出現(xiàn)執(zhí)行時(shí)間超過10秒的情況,連接超時(shí)。因此,根據(jù)需要,在創(chuàng)建數(shù)據(jù)源時(shí),增加設(shè)置SocketTimeout和ConnectTimeout的大小就可以避免再次出現(xiàn)上述錯(cuò)誤。文章來源地址http://www.zghlxwxcb.cn/news/detail-722525.html
到了這里,關(guān)于com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure錯(cuò)誤解決的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!