一剔应、背景
最近項目組在版本迭代時睡腿,組件也要進(jìn)行升級康谆,此時涉及到MySQL驅(qū)動包jdbc的版本升級。即從5.1.X升級到8.0.X嫉到。
然鵝在上線之后就出現(xiàn)了一部分兼容性問題,造成了一次“事故”:調(diào)用接口出現(xiàn)“系統(tǒng)錯誤”月洛。查看日志:java.time.LocalDateTime cannot be cast to java.util.Date何恶,也就是出現(xiàn)時間轉(zhuǎn)換異常。
二嚼黔、問題排查
根據(jù)異常堆棧细层,找到異常拋出的位置:
由此得知,使用mybatis進(jìn)行SQL的查詢時唬涧,使用的是Map來接收數(shù)據(jù)疫赎,key是字段名,value則是具體的數(shù)據(jù)碎节,且為Object捧搞,即可接收任何類型的對象數(shù)據(jù)。異常指出其Object具體為LocalDateTime狮荔,而不是Date類型胎撇。
根據(jù)git log知道,老代碼基本上沒改過殖氏,可能的原因就是本次MySQL驅(qū)動包的升級晚树,造成的。那么到底是為什么呢雅采?
本地環(huán)境進(jìn)行debug跟蹤爵憎,調(diào)整不同的MySQL驅(qū)動包mysql-connector-java,發(fā)現(xiàn)了最終的原因所在婚瓜。
MySQL 5.1.X版本:
可以看到宝鼓,MySQL驅(qū)動包處理datetime時間類型是使用java.sql.TimeStamp(extends Date)進(jìn)行構(gòu)造處理,最后轉(zhuǎn)化為Date類型闰渔。
調(diào)用棧如下:
MySQL 8.0.X版本:
通過MySQL 8.0.X驅(qū)動包源碼知道席函,DateTime類型的數(shù)據(jù)使用的是LocalDateTime,LocalDateTime是Java 8特性的冈涧。所以茂附,在新驅(qū)動版本中,已經(jīng)使用上Java 8的相關(guān)特性督弓。
調(diào)用棧如下:
三营曼、MySQL版本
接下來我們來了解下MySQL驅(qū)動包對于時間類型DateTime的問題跟蹤。
3.1愚隧、升級的原因及MySQL8.0版本新特性
1. 性能:MySQL 8.0 的速度要比 MySQL 5.7 快 2 倍蒂阱。MySQL 8.0 在以下方面帶來了更好的性能:讀/寫工作負(fù)載、IO 密集型工作負(fù)載、以及高競爭("hot spot"熱點競爭問題)工作負(fù)載录煤。
2. NoSQL:MySQL 從 5.7 版本開始提供 NoSQL 存儲功能鳄厌,目前在 8.0 版本中這部分功能也得到了更大的改進(jìn)。該項功能消除了對獨立的 NoSQL 文檔數(shù)據(jù)庫的需求妈踊,而 MySQL 文檔存儲也為 schema-less 模式的 JSON 文檔提供了多文檔事務(wù)支持和完整的 ACID 合規(guī)性了嚎。
3. 窗口函數(shù)(Window Functions):從 MySQL 8.0 開始,新增了一個叫窗口函數(shù)的概念廊营,它可以用來實現(xiàn)若干新的查詢方式歪泳。窗口函數(shù)與 SUM()、COUNT() 這種集合函數(shù)類似露筒,但它不會將多行查詢結(jié)果合并為一行呐伞,而是將結(jié)果放回多行當(dāng)中。即窗口函數(shù)不需要 GROUP BY慎式。
4. 隱藏索引:在 MySQL 8.0 中伶氢,索引可以被“隱藏”和“顯示”。當(dāng)對索引進(jìn)行隱藏時瞬捕,它不會被查詢優(yōu)化器所使用鞍历。我們可以使用這個特性用于性能調(diào)試,例如我們先隱藏一個索引肪虎,然后觀察其對數(shù)據(jù)庫的影響劣砍。如果數(shù)據(jù)庫性能有所下降,說明這個索引是有用的扇救,然后將其“恢復(fù)顯示”即可刑枝;如果數(shù)據(jù)庫性能看不出變化,說明這個索引是多余的迅腔,可以考慮刪掉装畅。
5. 降序索引:MySQL 8.0 為索引提供按降序方式進(jìn)行排序的支持,在這種索引中的值也會按降序的方式進(jìn)行排序沧烈。
6. 通用表表達(dá)式(Common Table Expressions CTE):在復(fù)雜的查詢中使用嵌入式表時掠兄,使用 CTE 使得查詢語句更清晰。
7. UTF-8 編碼:從 MySQL 8 開始锌雀,使用 utf8mb4 作為 MySQL 的默認(rèn)字符集蚂夕。
8. JSON:MySQL 8 大幅改進(jìn)了對 JSON 的支持,添加了基于路徑查詢參數(shù)從 JSON 字段中抽取數(shù)據(jù)的 JSON_EXTRACT() 函數(shù)腋逆,以及用于將數(shù)據(jù)分別組合到 JSON 數(shù)組和對象中的 JSON_ARRAYAGG() 和 JSON_OBJECTAGG() 聚合函數(shù)婿牍。
9. 可靠性:InnoDB 現(xiàn)在支持表 DDL 的原子性,也就是 InnoDB 表上的 DDL 也可以實現(xiàn)事務(wù)完整性了惩歉,要么失敗回滾等脂,要么成功提交俏蛮,不至于出現(xiàn) DDL 時部分成功的問題,此外還支持 crash-safe 特性上遥,元數(shù)據(jù)存儲在單個事務(wù)數(shù)據(jù)字典中搏屑。
10. 高可用性(High Availability):InnoDB 集群為您的數(shù)據(jù)庫提供集成的原生 HA 解決方案。
11. 安全性:對 OpenSSL 的改進(jìn)粉楚、新的默認(rèn)身份驗證睬棚、SQL 角色、密碼強(qiáng)度解幼、授權(quán)。
3.2包警、MySQL 驅(qū)動8.0.X版本對DateTime的變更
Also, with the implementation of the new mechanism, a?getObject(columnIndex)?call on a?DATETIME?column returns a?LocalDateTime?object now instead of a?String. To receive a?String?like before, use?getObject(columnIndex, String.class)?instead.
由此可見撵摆,針對DateTime類型的字段,在8.0.23的版本做了調(diào)整害晦,直接返回LocalDateTime類型特铝。
3.2、MySQL 驅(qū)動版本和Java版本的對應(yīng)關(guān)系
從上面知道壹瘟,MySQL 驅(qū)動包jdbc分成兩個分支版本5.1和8.0鲫剿,并且8.0版本是作為首選的推薦版本。
四稻轨、總結(jié)
1)做作何組件版本的升級灵莲,都要注意風(fēng)險,要慎重對待殴俱。新版本雖然好用政冻,但是兼容性問題都要盡量處理好,以免造成生產(chǎn)事故线欲。
2)MySQL驅(qū)動包jdbc新版本8.0支持了很多特性明场,但是要能了解到跟舊版本的區(qū)別及其調(diào)整了哪些內(nèi)容,以及存在的兼容問題李丰,都要一清二楚苦锨,可以羅列清單,將相關(guān)可能存在的問題考慮周全趴泌,對相關(guān)功能進(jìn)行回歸測試舟舒,這樣就可以比較好的平穩(wěn)升級。
參考資料:
1踱讨、MySQL和MySQL驅(qū)動mysql-connector-java升級到8.0.X版本
2魏蔗、Changes in MySQL Connector/J 8.0.23 (2021-01-18, General Availability)
3、Chapter 2 Connector/J Versions, and the MySQL and Java Versions They Require