Mysql 時間型別精度擷取的bug
mysql-connector-java版本升級出現的一次問題。涉及到了時間精度的擷取和四捨五入。
首先了解一點,timestamp,datetime如果不指定精度,預設的精度是秒。
當mysql-connector-java版本<=5.1.22時,db的客戶端會將Datetime,Timestamp秒以下的精度丟棄。版本>5.1.22後,秒以下的值將不會截斷
db的server端會對超出精度位數的資料進行四捨五入!!
舉個例子:在db建表時沒指定精度時,插入精確到毫秒級別的日期
如果使用mysql-connector-java版本<=5.1.22,在客戶端用'2018-04-02 23:59:59.999'插入日期,精度會在客戶端被擷取到秒,插入db裡是'2018-04-02 23:59:59'
如果升級版本,在db的客戶端用'2018-04-02 23:59:59.999'插入日期,精度在客戶端不會被截斷,db的server端會對超出精度位數的資料進行四捨五入,即插入db裡是'2018-04-03 00:00:00 '
所以說mysql-connector-java版本升級就帶了時間與原本不一致的問題,結合具體業務邏輯上的使用,可能會造成不同大小的影響。
要想證實這個觀點,可以分兩步:
- server端是否會四捨五入
- 客戶端程式碼不同版本對精度是否有不同的處理方式
來實際測一下server會不會四捨五入:
CREATE TABLE `time_test` ( `id` int(11) NOT NULL AUTO_INCREMENT , `create_time` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' , `end_time` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00' , PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; insert into time_test (create_time,end_time) values('2018-04-02 23:59:59','2018-04-02 23:59:59.999'); select * from time_test;
看一下記錄:
+----+---------------------+---------------------+
| id | create_time | end_time |
+----+---------------------+---------------------+
|
2
|
2018
-
04
-
02
23
:
59
:
59
|
2018
-
04
-
03
00
:
00
:
00
|
+----+---------------------+---------------------+
可以看出db的server端果然會進行四捨五入。
再看一下mysql驅動裡是怎麼寫的,是否真的是截斷精度了。
Mysql對於時間精度的處理在com.mysql.jdbc.PreparedStatement#setTimestampInternal這個方法中
翻一下5.1.21的原始碼看一下:
private void setTimestampInternal(int parameterIndex, Timestamp x, Calendar targetCalendar, TimeZone tz, boolean rollForward) throws SQLException { synchronized (checkClosed()) { if (x == null) { setNull(parameterIndex, java.sql.Types.TIMESTAMP); } else { checkClosed(); if (!this.useLegacyDatetimeCode) { newSetTimestampInternal(parameterIndex, x, targetCalendar); } else { String timestampString = null; Calendar sessionCalendar = this.connection.getUseJDBCCompliantTimezoneShift() ? this.connection.getUtcCalendar() : getCalendarInstanceForSessionOrNew(); synchronized (sessionCalendar) { x = TimeUtil.changeTimezone(this.connection, sessionCalendar, targetCalendar, x, tz, this.connection .getServerTimezoneTZ(), rollForward); } if (this.connection.getUseSSPSCompatibleTimezoneShift()) { doSSPSCompatibleTimezoneShift(parameterIndex, x, sessionCalendar); } else { synchronized (this) { if (this.tsdf == null) { //這裡,截斷秒以下的精度 this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US); //$NON-NLS-1$ } timestampString = this.tsdf.format(x); //這裡永遠不會執行新增秒以下的精度 if (false) { // not so long as Bug#50774 is around StringBuffer buf = new StringBuffer(); buf.append(timestampString); int nanos = x.getNanos(); if (nanos != 0) { buf.append('.'); buf.append(formatNanos(nanos)); } buf.append('\''); } setInternal(parameterIndex, timestampString); // SimpleDateFormat is not // thread-safe } } } this.parameterTypes[parameterIndex - 1 + getParameterIndexOffset()] = Types.TIMESTAMP; } } }
再看下5.1.32的實現:
private void setTimestampInternal(int parameterIndex, Timestamp x, Calendar targetCalendar, TimeZone tz, boolean rollForward) throws SQLException { synchronized (checkClosed().getConnectionMutex()) { if (x == null) { setNull(parameterIndex, java.sql.Types.TIMESTAMP); } else { checkClosed(); if (!this.useLegacyDatetimeCode) { newSetTimestampInternal(parameterIndex, x, targetCalendar); } else { Calendar sessionCalendar = this.connection.getUseJDBCCompliantTimezoneShift() ? this.connection.getUtcCalendar() : getCalendarInstanceForSessionOrNew(); synchronized (sessionCalendar) { x = TimeUtil.changeTimezone(this.connection, sessionCalendar, targetCalendar, x, tz, this.connection .getServerTimezoneTZ(), rollForward); } if (this.connection.getUseSSPSCompatibleTimezoneShift()) { doSSPSCompatibleTimezoneShift(parameterIndex, x, sessionCalendar); } else { synchronized (this) { //同樣截斷精度 if (this.tsdf == null) { this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss", Locale.US); //$NON-NLS-1$ } StringBuffer buf = new StringBuffer(); buf.append(this.tsdf.format(x)); //這裡,如果server支援fractional seconds的話,就加上毫秒的精度 if (this.serverSupportsFracSecs) { int nanos = x.getNanos(); if (nanos != 0) { buf.append('.'); buf.append(TimeUtil.formatNanos(nanos, this.serverSupportsFracSecs, true)); } } buf.append('\''); setInternal(parameterIndex, buf.toString()); // SimpleDateFormat is not // thread-safe } } } this.parameterTypes[parameterIndex - 1 + getParameterIndexOffset()] = Types.TIMESTAMP; } } }
看來果然是個bug...看一下mysql官網的描述:參見bugFix第三條
相關推薦
Mysql 時間型別精度擷取的bug
mysql-connector-java版本升級出現的一次問題。涉及到了時間精度的擷取和四捨五入。 首先了解一點,timestamp,datetime如果不指定精度,預設的精度是秒。 當mysql-connector-java版本<=5.1.22時,db的客戶端會將Datetime,Timestam
MySQL時間型別和long型別的轉換,日期格式化
MySQL中可以將時間型別儲存為long型別資料: UNIX時間戳轉換為日期用函式: FROM_UNIXTIME() select FROM_UNIXTIME(1536148611); 日期轉換為UNIX時間戳用函式: UNIX_TIMESTAMP() Select U
mysql 時間型別精確到毫秒、微秒及其處理
一、MySQL 獲得毫秒、微秒及對毫秒、微秒的處理 MySQL 較新的版本中(MySQL 6.0.5),也還沒有產生微秒的函式,now() 只能精確到秒。 MySQL 中也沒有儲存帶有毫秒、微秒的日期時間型別。 但,奇怪的是 MySQL 已經有抽取(extract)微秒的函式。例如: select mi
MySQL 時間型別datetime欄位 精確到毫秒問題
今天遇到一個小問題,計算一筆操作的執行時間,操作前先用LocalDateTime(本人是Java開發者)記錄開始時間且寫入資料庫,操作完成後計算操作完成時間和開始時間的時間差,結果算出來出現了負數結果。 在日誌中打印出來,發現結果是從資料庫取出的開始時間後三位毫秒都是0,而
[轉]MySQL:MySQL日期資料型別、MySQL時間型別使用總結
[轉自]http://www.blogjava.net/titanaly/archive/2009/08/17/291454.html MySQL:MySQL日期資料型別、MySQL時間型別使用總結 MySQL 日期型別:日期格式、所佔儲存空間、日期範圍 比較。
mysql 時間型別精確到毫秒、微秒及其處理
select * from test where DATE_FORMAT(timess,'%Y-%m-%d %T:%f') between DATE_FORMAT('2010-12-01 06:03:16.233','%Y-%m-%d %T:%f') and DATE_FORMAT('2010-12-01
mysql時間型別timestamp知識點
mysql日期時間型別 日期型別 位元組 最小值 最大值 DATE 4 1000-01-01 9999-12-31 DATETIME 8 1000-01-01 00:00:00 TimeS
一起MySQL時間戳精度引發的血案
寫在前面 最近工作中遇到兩例mysql時間戳相關的問題,一個是mysql-connector-java和msyql的精度不一致導致資料查不到;另一例是應用伺服器時區錯誤導致資料查詢不到。通過這篇文章,希望能夠解答關於mysql中時間戳的幾個問題: mysql中的DATETIME精度為什麼只支援到秒? mys
MySQL - 日期時間型別與格式化
【1】MySQL中的日期時間型別 MySQL中常用的幾種時間型別有:date、datetime、time、year、timestamp; ① 詳細解釋 Datetime : 時間日期型,格式是YYYY-mm-dd HH:ii:ss,表示的範圍是從1000到9999。但是有零值,0000-
Mysql中時間戳格式和時間型別格式的裝換
首先我有這樣一個時間 將此時間轉換為時間戳格式: SELECT UNIX_TIMESTAMP(pst.ep_order_time) AS ep_order_time FROM prj_status_time pst WHERE pst.project_id='15414878732
Java與MySQL資料對接時的時間型別的資料
使用java.util.Date與MySQL資料庫的時間欄位對接時,獲取到的時間是格林格式的,還需要進行一下轉換才能使用為本地時間,偶然發現一篇部落格,這引用一下java.sql.date 以前從MySQL中查詢出來的時間日期型別,都放在java.util.Date型別裡面了。這樣帶
MySQL資料型別 -- 日期時間型
在MySQL關係型資料庫中,MySQL支援的資料型別非常豐富。它主要分為3大類,即:數值型,日期時間性,字元型。而實際上這三類資料型別可以進一步的細分擴充套件,可以根據業務需要選擇最適合的一種。本文主要介紹日期時間型別,並演示其用法。 一、日期時間型 MySQL
mysql的資料型別之日期時間型別
常用的日期時間型別: DATE ;TIME; DATETIME ;TIMESTAMP 。 (1)根據實際需要選擇滿足應用的最小儲存的日期型別 (2)記錄年份比較久遠,最好要使用DATETIME。因為TIMESTAMP表示的日期範圍要短很多。 (3)如果讓不同的時區保持
mysql的五種日期和時間型別【轉載】
[mysql的五種日期和時間型別] mysql(5.5)所支援的日期時間型別有:DATETIME、 TIMESTAMP、DATE、TIME、YEAR。 幾種型別比較如下: 日期時間型別 佔用空間 日期格式 最小值 最大值 零值表示
【小家SQL】MySql資料型別---日期時間型別的使用(含datetime和timestamp的區別)
每篇一句 練武不練功,到老一場空。 程式設計師應該注重內功的修煉,那才是核心競爭力 說在前面 在這一路學習過來,每次不管看書還是網上看的資料,對於MySQL資料型別中的時間日期型別總是一掃而過,不曾停下來認認真真的研究學習。最近看了一本關於MySql的書
MySQL中時間型別DATETIME、TIMESTAMP、DATE、TIME、YEAR
1.幾個的區別 詳細可以參考:https://www.cnblogs.com/Jie-Jack/p/3793304.html 2.針對時間型別的一些操作 nodejs支援多種格式轉換為時間戳: var str1 = "2017-01-19 13:00:00"; va
MySQL 幾種日期時間型別之間的區別
mysql(5.5)所支援的日期時間型別有:DATETIME、 TIMESTAMP、DATE、TIME、YEAR。 幾種型別比較如下: 日期時間型別 佔用空間 日期格式 最小值 最大值 零值表示 DATETIME 8 bytes YYYY-MM-DD HH:MM:SS 1000-01-01
MySQL幾種資料型別精度和標度的情況
1、整型 int預設是int(11),建立欄位int(5),當儲存的資料長度大於5時,可以正常儲存,儲存的資料完整顯示; 2、浮點型 float(M,D)和double(M,D) 如果不寫精度和標度,則會按照實際精度值顯示,如果有精度和標度,則會自動將四捨五入的結果插入,不
一個 double 型別精度問題導致的 Bug
在寫 Weex 的時候,遇到一個 Bug —— 顯示的訂單 ID 不對,和 API 測試平臺獲取的資料不一致。首先懷疑的是取錯欄位了,認真檢查了一下,不是這個原因。然後懷疑的是 Native 網路請求模組 JsonString 轉 Model 的時候出錯
Java、MySql中時間型別與字串型別的相互轉換
很多時候,我們在做專案的時候經常會遇到前臺傳回來的時間引數。有的時候,前臺會做處理,將文字框的字串轉化為時間型別的;有的時候,前臺就直接傳字串型別的,所以,作為後臺開發人員要知道,資料庫中時間型別與字串的相互轉換。 1.MySql中時間型別與字串型別相互