一塊兒MySQL時間戳精度引起的血案

寫在前面

最近工做中遇到兩例mysql時間戳相關的問題,一個是mysql-connector-java和msyql的精度不一致致使數據查不到;另外一例是應用服務器時區錯誤致使數據查詢不到。經過這篇文章,但願可以解答關於mysql中時間戳的幾個問題:html

  1. mysql中的DATETIME精度爲何只支持到秒?
  2. mysql中的DATETIME類型跟時區有關嗎?
  3. mysql設計表的時候,表示時間的字段改如何選擇?

案例分析 DATETIME的精度問題

前段時間,將負責的應用的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

    22.png

  • 在查詢以前,將傳入的時間戳減1秒;app

通過驗證,方案1會,java.util.Date轉過去的java.sql.Date對象會將日期以後的精度所有丟掉,從而致使查詢出更多沒必要要的數據;方案3是能夠的,就是可能會查出多一兩條數據;方案2也是能夠的,至關於從代碼上對mysql-connector-java的特性作了補償。最終我選擇的是方案2。框架

案例復現

利用homebrew安裝MySQL,版本是8.0.15,裝好後建一個表,用來存放用戶信息,SQL以下:

55.png

使用spirngboot + mybatis做爲開發框架,定義一個用戶實體,代碼以下所示:

44.png

定義該實體對應的Mapper,代碼以下:

33.png

設置鏈接mysql相關的配置,代碼以下:

image.png

編寫測試代碼,先插入一條數據,而後用時間戳做爲查詢條件去查詢,代碼以下:

image.png

運行單測,如咱們的設想,確實是沒有查詢出數據來,結果以下:

image.png

而後修改代碼,利用上面的代碼將查詢的時間戳按秒取正,代碼以下:

image.png

再次運行單測,如咱們的設想,此次能夠查詢出數據來了。

不過,這裏有個小插曲,我在最開始設計表的時候,使用的SQL語句是下面這樣的,

SQL_2.png

聰明如你必定發現了,這裏的datetime已經支持小數點後更小的時間精度了,最多支持6位即最多能夠支持到微妙級別。這個特性是何時引入的呢,我去查閱了[MySQL的官方文檔][9],發現這個特性是在mysql 5.6.4以後開始支持的。

image.png

知識點總結

通過了前面的實際案例分析和案例復現,想必讀者已經對mysql中DATETIME這個類型有了必定的認識,接下來跟我一塊兒看下,咱們從這個案例中能夠總結出哪些經驗。

  1. mysql-connector-java的版本和mysql的版本須要配套使用,例如5.6.4以前的版本,就最好不要使用mysql-connector-java的5.1.23以後的版本,不然就可能會遇到咱們此次遇到的問題。
  2. MySQL中用來表示時間的字段類型有:DATE、DATETIME、TIMESTAMP,它們之間有相同點,各自也有本身的特性,我總結了一個表格,以下所示:
    image.png
  3. DATETIME類型在MySQL中是以「YYYYMMDDHHMMSS」格式的整數存放的,與時區無關,使用8個字節的空間;
  4. TIMESTAMP類型能夠保存的時間範圍要小不少,顯示的值依賴時區,MySQL的服務器、操做系統以及客戶端鏈接都有時區的設置。
  5. 通常狀況下推薦使用DATETIME做爲時間戳字段,不推薦使用bigint類型來存儲時間。
  6. 在開發中,應該儘可能避免使用時間戳做爲查詢條件,若是必需要用,則須要充分考慮MySQL的精度和查詢參數的精度等問題。

參考資料

  1. dev.mysql.com/doc/refman/…
  2. 《高性能MySQL》

本號專一於後端技術、JVM問題排查和優化、Java面試題、我的成長和自我管理等主題,爲讀者提供一線開發者的工做和成長經驗,期待你能在這裏有所收穫。

javaadu
相關文章
相關標籤/搜索