問題描述
App Service使用jdbc連線MySQL服務,出現大量的 Communications link failure:
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server
問題分析
最開始出現連線不上的原因,懷疑是MySQL服務的IP地址白名單沒有配置正確的App Service 出站IP。但是根據錯誤提示,發現明顯不對,因為如果是IP地址不允許訪問,它的錯誤訊息應該是:
Client with IP address '183.2xx.xx.xx' is not allowed to connect to this MySQL server.
所以不應該是MySQL伺服器對IP白名單設定的問題。
為了深入找出問題,單獨用Java Spring Boot來寫一個簡單的資料庫連線程式碼,根據MySQL官方的程式碼:https://docs.azure.cn/zh-cn/mysql/connect-java
POM.XML內容為:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <properties> <java.version>1.8</java.version> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.20</version> </dependency> </dependencies> </project>
注:這裡使用的 mysql-connector-java 依賴版本為 8.0.20
Java Main函式程式碼:
public static void main(String[] args) { String url = "jdbc:mysql://xxxxxx.mysql.database.chinacloudapi.cn:3306/xxxxxx?useSSL=true&requireSSL=false&characterEncoding=utf8&serverTimezone=UTC"; String username = "xxxxxx@xxxxxx"; String password = "xxxxxxxxxxxx"; try { Connection connection = DriverManager.getConnection(url, username, password); System.out.println(connection.getMetaData().getURL()); connection.close(); System.out.println("connected!"); } catch (SQLException e) { // TODO Auto-generated catch block System.out.println(e.getMessage()); return; // return because nothing can be done w/out a connection } }
同樣的資料庫連線字串,執行結果正常。根據驗證結果對比,出現 Communications link failure | The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server, 的JDBC版本為 8.0.15, 所以瞬間定位問題原因:客戶端jdbc的驅動問題。
根據這一判斷,再次檢查了MySQL的版本為8.0並且為單例項(Single Server)。而微軟的官方文件中提示了 use 8.0.17+ with MySQL 8.0 (https://docs.microsoft.com/en-us/azure/mysql/concepts-compatibility#mysql-drivers)
隨後,對mysql-connector jdbc的版本 8.0.17, 8.0.18, 8.0.19 這三個版本進行驗證,看是否不會出現 Communications link failure 異常:
8.0.17 Error
8.0.18 Error
8.0.19 Successful
經過以上驗證,得出微軟官方文件中的 8.0.17+有問題,需要在8.0.19+的驅動版本後才能成功。(一個調查了三天的大坑)
參考資料
將 Java 和 JDBC 與 Azure Database for MySQL 配合使用 : https://docs.azure.cn/zh-cn/mysql/connect-java