首頁 > 軟體

Mysql DateTime 查詢問題解析

2022-11-28 22:02:38

正文

 /**
 * The maximum supported {@code LocalTime}, '23:59:59.999999999'.
 * This is the time just before midnight at the end of the day.
 */
 public static final LocalTime MAX;
 /**
  * The maximum supported {@code LocalDateTime}, '+999999999-12-31T23:59:59.999999999'.
  * This is the local date-time just before midnight at the end of the maximum date.
  * This combines {@link LocalDate#MAX} and {@link LocalTime#MAX}.
  * This could be used by an application as a "far future" date-time.
  */
 public static final LocalDateTime MAX = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX);

我們可以看到 LocalTime 和 LocalDateTime 的精度是可以去到 9 也就是達到納秒

但是為什麼我們經常列印出來的時候往往只有小數點後三位、也就是毫秒

 LocalDateTime now = LocalDateTime.now();
 System.out.println(now);

呼叫System的currentTimeMillis

我們看到原始碼最終還是呼叫了 System的currentTimeMillis

 @Override
 public long millis() {
     return System.currentTimeMillis();
 }
 @Override
 public Instant instant() {
     return Instant.ofEpochMilli(millis());
 }

最近測試環境中出現了個時間精度的問題、計算某個流程所花費的時間的時候得出了負數、因為儲存該欄位的型別設定了無符號、導致插入的時候報錯、超出該型別的值的範圍。

當時的第一反應是流程對應的步驟是不是分別在不同的容器中執行、容器之間是否存在時間差。

後面排查所有的步驟均執行在同一個容器中、紀錄檔列印的時間和sql插入的值均沒啥差異。select 出來的值沒有列印出來。

後面看到其中紀錄檔列印insert 的值的秒比資料庫中的秒要少一秒。然後發覺沒有設定 dateTime 的精度

這個其實是錄入表的同事遺漏了、原本設計表結構是有6位精度的(規範要求)。

後面補上精度、順手將無符號也去掉

Mysql 中的 dateTime 精度預設為 0 、最大可以去到 6。

如果入參的精度大於 dateTime 的精度、那麼將會進行四捨五入。

小結

插入的時候、如果輸入的精度比宣告的精度高、那麼則會對其進行四捨五入

查詢

值得注意的是、LocalTime | LocalDateTime 的 MAX 是 9位 的、如果

 drop table mqst1;
 create table mqst1
 (
     id         int      null,
     createtime datetime(0) null
 );
 INSERT INTO test_schema.mqst1 (id, createtime) VALUES (1, '2021-10-01 21:08:08.123');
 INSERT INTO test_schema.mqst1 (id, createtime) VALUES (1, '2021-10-01 23:59:59.567');
 INSERT INTO test_schema.mqst1 (id, createtime) VALUES (2, '2021-10-02 00:00:00.000');
 select *
 from mqst1
 where createtime >= '2021-10-01 00:00:00'  and createtime <= '2021-10-01 23:59:59.999999';
 select *
 from mqst1
 where createtime >= '2021-10-01 00:00:00' and createtime <= '2021-10-01 23:59:59.9999995';

第二條的查詢就最後的引數比第一條的時間多了一個 5

首先看插入結果

那麼第一條的查詢結果是隻有一條

第二條的查詢結果卻是 3 條。

因為 mysql 將字串轉換成 dateTime 的時候使用的是 6 位的精度、超過六位的才會四捨五入、所以導致第二條的查詢條件變為 10-02 00:00:00

我們將 dateTime 的精度改為 2

 createtime datetime(2) null

那麼第一條的查詢結果為兩條

而第二條的查詢結果還是為三條

即使將精度改為6也是這樣的結果

總結

對於查詢而已、mysql 會對 string 的轉換如果超出 6 位 多出的會進行四捨五入、然後才會去表中進行比較

事實上對於大多數場景而已、Java 提供的毫秒級別的時間以及能滿足大多數場景了、對應到 db 儲存時間到精度、

建議直接 6 會比較省心點吧、跟 Mysql 做字串轉換 dateTime 的時候一樣。

查詢到時候需要注意的是如果上限被包含進去、需要考慮精度是否超過 Mysql 的最大精度、如果超過了則可能你會被舍入

 System.out.println(LocalDateTime.of(LocalDate.now(), LocalTime.MAX).withNano(999999000));

以上就是Mysql DateTime查詢問題解析的詳細內容,更多關於Mysql DateTime的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com