最近工做中遇到兩例mysql時間戳相關的問題,一個是mysql-connector-java和msyql的精度不一致致使數據查不到;另外一例是應用服務器時區錯誤致使數據查詢不到。經過這篇文章,但願可以解答關於mysql中時間戳的幾個問題:html
前段時間,將負責的應用的mysql-connector-java的版本從5.1.16升級到5.1.30,在作功能迴歸的時候發現,使用了相似上面的SQL的用例的運行時數據會有遺漏,致使功能有問題。java
考慮到我負責的應用中,有個功能須要用到相似下面這種SQL,即便用時間戳做爲查詢的條件,查詢在某個時間戳以後的全部數據。 mysql
通過排查發現:mysql-connector-java在5.1.23以前會將秒後面的精度丟棄再傳給MySQL服務端,正好咱們使用的mysql版本中DATETIME的精度是秒;在我將mysql-connector-java升級到5.1.30後,從java應用經過mysql-connector-java將時間戳傳到MySQL服務端的時候,就不會將毫秒數丟棄了,從mysql-connector-java的角度看是修復了一個BUG,可是對於個人應用來講倒是觸發了一個BUG。面試
若是你面對這個問題,你會怎麼修復呢?sql
咱們當時想了三種方案:後端
將mybatis的Mapper接口中的時間戳參數的類型,從java.util.Date改爲java.sql.Date;服務器
在傳入Mapper接口以前,將傳入的時間戳按秒取正,代碼以下mybatis
在查詢以前,將傳入的時間戳減1秒;app
通過驗證,方案1會,java.util.Date轉過去的java.sql.Date對象會將日期以後的精度所有丟掉,從而致使查詢出更多沒必要要的數據;方案3是能夠的,就是可能會查出多一兩條數據;方案2也是能夠的,至關於從代碼上對mysql-connector-java的特性作了補償。最終我選擇的是方案2。框架
利用homebrew安裝MySQL,版本是8.0.15,裝好後建一個表,用來存放用戶信息,SQL以下:
使用spirngboot + mybatis做爲開發框架,定義一個用戶實體,代碼以下所示:
定義該實體對應的Mapper,代碼以下:
設置鏈接mysql相關的配置,代碼以下:
編寫測試代碼,先插入一條數據,而後用時間戳做爲查詢條件去查詢,代碼以下:
運行單測,如咱們的設想,確實是沒有查詢出數據來,結果以下:
而後修改代碼,利用上面的代碼將查詢的時間戳按秒取正,代碼以下:
再次運行單測,如咱們的設想,此次能夠查詢出數據來了。
不過,這裏有個小插曲,我在最開始設計表的時候,使用的SQL語句是下面這樣的,
聰明如你必定發現了,這裏的datetime已經支持小數點後更小的時間精度了,最多支持6位即最多能夠支持到微妙級別。這個特性是何時引入的呢,我去查閱了[MySQL的官方文檔][9],發現這個特性是在mysql 5.6.4以後開始支持的。
通過了前面的實際案例分析和案例復現,想必讀者已經對mysql中DATETIME這個類型有了必定的認識,接下來跟我一塊兒看下,咱們從這個案例中能夠總結出哪些經驗。
本號專一於後端技術、JVM問題排查和優化、Java面試題、我的成長和自我管理等主題,爲讀者提供一線開發者的工做和成長經驗,期待你能在這裏有所收穫。