最近從MS SQL Server換到了MySQL,已經是8.11版本了,安裝的時候似乎還用了新的身份認證方式之類的,連接過程中也是磕磕絆絆,碰到很多奇奇怪怪的問題,在此記錄下來。
驅動加載:
以前使用JDBC時,都是導入相應的JDBC驅動jar包,然后使用
Class.forName(driverName);
加載驅動,再進行數據庫連接,在使用MySQL 8.11版本及其對應的Connector時,如果使用上述代碼加載com.mysql.jdbc.Driver的話,控制台會輸出一行信息:
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
大概意思是加載的這個類已被棄用,新驅動類是com.mysql.cj.jdbc.Driver,通過SPI自動注冊,通常不需要手動加載。注釋掉Class.forName后運行就不會產生該輸出了。
連接數據庫時的URL:
URL前半部分格式固定,需要附加的參數是通過類似網址中的QueryString附着在后面的,格式如下:
jdbc:<_database>://<address>:<port>/<database_name>[?_key1=_value1[&_key2=_value2[&_key3=_value3]...]]
在此僅列舉用到的幾個參數:
不加參數進行連接時首先會輸出這樣一行提示信息:
Tue May 08 20:16:40 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
大概意思是不建議在沒有服務器身份驗證的情況下建立SSL連接等等,由於本人對SSL並不了解,就直接按照提示在加上參數useSSL=false,就不會產生該輸出了。
接下來遇到的錯誤是一個關於時區的SQLException:The server time zone value......
java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
大概意思是服務器的時區值有問題,我這直接就是一團亂碼了,按照提示加上參數serverTimezone=Hongkong,就不會產生這個異常了,對於該參數的取值可以查閱相關資料獲得,已知東8區可以用Hongkong、Asia/Shanghai或者Asia/Hongkong作為參數取值。
SQLNonTransientConnectionException: Public Key Retrieval is not allowed
這時可能程序已經能夠正常連接數據庫了,不過我在調試成功后第二天再次連接時(未對代碼進行改動),拋出了一個異常並連接失敗,多次嘗試無果,該異常如下:
SQLNonTransientConnectionException: Public Key Retrieval is not allowed
對於這個異常網上相關資料很少,多為英文,誤打誤撞下竟然解決了這個問題,方法為添加一個參數allowPublicKeyRetrieval=true,即可正常連接,而且在連接成功一次后,刪除此參數仍然可以正常連接(不懂得都是玄學)......,該方法來自(https://bugs.mysql.com/bug.php?id=75670)下一位dalao的評論:
[20 Aug 2015 19:57] Daniel So Added the following entry to the Connector/J 6.0 changelog: "If the MySQL server's default authentication method was SHA256 but neither one of the Connector/J connection properties allowPublicKeyRetrieval and serverRSAPublicKeyFile was set, the authentication failed with a TransientConnectionException, complaining that the public key could not be retrieved. With this fix, authentication continues in the situation, allowing other enabled authentication methods to be tried."
然而並沒有看懂。
另外就是字符編碼問題,本人服務器默認使用的編碼為UTF-8MB4,Eclipse默認編碼均使用UTF-8,所以並未處理編碼問題。
若需要進行編碼轉換需要附加參數useUnicode=true 和 characterEncoding=UTF-8。
其他重要參數(轉自:https://blog.csdn.net/wpydaguan/article/details/41148047):
參數名稱 | 參數說明 | 缺省值 | 最低版本要求 |
user | 數據庫用戶名(用於連接數據庫) | 所有版本 | |
password | 用戶密碼(用於連接數據庫) | 所有版本 | |
useUnicode | 是否使用Unicode字符集,如果參數characterEncoding設置為gb2312或gbk,本參數值必須設置為true | false | 1.1g |
characterEncoding | 當useUnicode設置為true時,指定字符編碼。比如可設置為gb2312或gbk | false | 1.1g |
autoReconnect | 當數據庫連接異常中斷時,是否自動重新連接? | false | 1.1 |
autoReconnectForPools | 是否使用針對數據庫連接池的重連策略 | false | 3.1.3 |
failOverReadOnly | 自動重連成功后,連接是否設置為只讀? | true | 3.0.12 |
maxReconnects | autoReconnect設置為true時,重試連接的次數 | 3 | 1.1 |
initialTimeout | autoReconnect設置為true時,兩次重連之間的時間間隔,單位:秒 | 2 | 1.1 |
connectTimeout | 和數據庫服務器建立socket連接時的超時,單位:毫秒。 0表示永不超時,適用於JDK 1.4及更高版本 | 0 | 3.0.1 |
socketTimeout | socket操作(讀寫)超時,單位:毫秒。 0表示永不超時 | 0 | 3.0.1 |
特別注意!在某些通過配置文件來指定URL的情況下(如xml配置文件),URL后參數的隔離符號&需要使用&轉義為&,其他符號也是如此:
HTML中常用的特殊字符(Character Entities)
顯示結果 | 說明 | Entity Name | Entity Number |
---|---|---|---|
顯示一個空格 | |
  |
|
< | 小於 | < |
< |
> | 大於 | > |
> |
& | &符號 | & |
& |
“ | 雙引號 | " |
" |
其他常用的字符實體(Character Entities)
顯示結果 | 說明 | Entity Name | Entity Number |
---|---|---|---|
? | 版權 | © |
© |
? | 注冊商標 | ® |
® |
× | 乘號 | × |
× |
÷ | 除號 | ÷ |
÷ |
Java Web中遇到的坑:
No suitable driver found for jdbc:mysql://...
前面提到MySQL啟用的舊驅動使用了新的通過SPI自動注冊的驅動,在普通Java程序下可以正常運行,但是在Java Web項目中運行在Tomcat8.5環境下時,進行數據庫連接操作會拋出異常:
java.sql.SQLException: No suitable driver found for jdbc:mysql://...
大概的意思是找不到合適的JDBC驅動程序,經過檢查,已經將使用到的驅動jar包放到了Tomcat的lib目錄下,Eclipse中的構建路徑也包含了該jar包,在執行連接操作前向控制台打印所用驅動類也存在:
System.out.println(com.mysql.cj.jdbc.Driver.class); /* *輸出: ** *class com.mysql.cj.jdbc.Driver * */
經過搜索得到的答案基本一致(轉自:http://www.blogjava.net/w2gavin/articles/217864.html):
今天出現編碼出現了No suitable driver found for jdbc,又是找遍了網上的資料,基本上都說是三個問題: 一是:連接URL格式出現了問題(Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/XX","root","XXXX") 二是:驅動字符串出錯(com.mysql.jdbc.Driver) 三是Classpath中沒有加入合適的mysql_jdbc驅動 經過我的仔細檢查,這三種錯誤我都沒有犯,為什么呢? 嘗試着將mysql-connector-java-3.1.14-bin.jar的jar包加入C:\Program Files\Java\jre1.6.0_02\lib\ext文件夾下,問題解決了!! 原來是不僅僅要求將驅動加入classpath中,而且需要將該jar包加入到java運行環境的外部jar包中,唉,下次這種低級錯誤還是少犯為妙。
對於這三個說法,本人針對前兩條進行了檢查,並沒有錯誤,第三條個人認為不正確,Tomcat會自動加載lib下的jar包,況且上面在打印驅動類的Class對象時也確實能看到該類已經被加載,對於下面將驅動jar包放入系統jre下的方(玄)法(學)也並未嘗試,不過,在連接數據庫操作前加了主動加載驅動類的代碼后竟然神(玄)奇(學)的好了:
System.out.println(com.mysql.cj.jdbc.Driver.class); Class.forName(driverName); System.out.println("connecting..."); conn = DriverManager.getConnection(URL, uName, uPwd); System.out.println("connect success!"); /* *輸出: ** *class com.mysql.cj.jdbc.Driver *connecting... *connect success! * */
可以看到在手動加載之前該類已經注冊,因此這個玄學問題還希望請知道的dalao指教一二!
目前遇到的問題就這些,日后遇到新的問題繼續補充,文中理解的若有錯誤還請dalao們指正,歡迎大家的討論交流。