1. 程式人生 > >mysql 5.5和5.6版本關於timestamp插null和0的處理

mysql 5.5和5.6版本關於timestamp插null和0的處理

Server version: 5.5.33-31.1-log Percona Server (GPL), Release rel31.1, Revision 566

mysql> CREATE TABLE `t1` (
`ID` int(11) NOT NULL DEFAULT ‘1‘,
`NAME` varchar(10) NOT NULL DEFAULT ‘‘,
`CREATE_TIME` timestamp NOT NULL DEFAULT ‘0000-00-00 00:00:00‘
) ENGINE=InnoDB DEFAULT CHARSET=utf8

mysql> select * from t1;
Empty set (0.00 sec)

mysql> insert into t1 (create_time) values (null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t1; +----+------+---------------------+ | ID | NAME | CREATE_TIME | +----+------+---------------------+ | 1 | | 2015-04-15 17:27:09 | +----+------+---------------------+ 1 row in set (0.00 sec)

從上面實驗看,在5.533版本中,create_time雖然定義為not null ,但是實際是能插入null只的,而且自動轉換為了current_time。接下來看5.6的操作:
Server version: 5.6.22-71.0-log Percona Server (GPL), Release 71.0, Revision 726

mysql> CREATE TABLE `t1` (
`ID` int(11) NOT NULL DEFAULT1‘,
`NAME` varchar(10) NOT NULL DEFAULT ‘‘,
`CREATE_TIME` timestamp NOT NULL DEFAULT0000-00-00 00:00:00‘
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

mysql> select * from t1;
Empty set (0.00 sec)

mysql> insert into t1 (create_time) values (null);
ERROR
1048 (23000): Column ‘CREATE_TIME‘ cannot be null mysql> select * from t1; Empty set (0.00 sec)

直接報錯,攔截語句插入。在5.6中是通過開啟引數來實現解決這個BUG的。下面是摘自官方文件的描述

With explicit_defaults_for_timestamp enabled, inserting NULL into a
TIMESTAMP NOT NULL column now produces an error (as it already did for other NOT NULL data types),
instead of inserting the current timestamp. (Bug #68472, Bug #16394472)

故如果想實現,插入到timestamp中的null變為當前時間的話,需要將explicit_defaults_for_timestamp設為關閉狀態

SET GLOBAL explicit_defaults_for_timestamp = off;

當資料庫為嚴格模式時,STRICT_TRANS_TABLES;嚴格模式不允許非法日期,例如’2004-04-31’。不允許日期使用“零”部分,例如’2004-04-00’或“零”日期。要想禁止,應在嚴格模式基礎上,啟用NO_ZERO_IN_DATENO_ZERO_DATE SQL模式。

NO_ZERO_DATE
在嚴格模式,不要將 ‘0000-00-00’做為合法日期。你仍然可以用IGNORE選項插入零日期。在非嚴格模式,可以接受該日期,但會生成警告。

NO_ZERO_IN_DATE
在嚴格模式,不接受月或日部分為0的日期。如果使用IGNORE選項,我們為類似的日期插入’0000-00-00’。在非嚴格模式,可以接受該日期,但會生成警告。

設定了這兩個引數時,插入到timestamp中的0將被拒絕操作;如果沒有設定著兩個引數,插入到timestamp中的0將變為’0000-00-00 00:00:00’預設值

從 5.6開始,timestamp 的預設行為已經是 deprecated 了。

在MySQL 5.6.6之前,TIMESTAMP的預設行為:

TIMESTAMP列如果沒有明確宣告NULL屬性,預設為NOT NULL。(而其他資料型別,如果沒有顯示宣告為NOT NULL,則允許NULL值。)設定TIMESTAMP的列值為NULL,會自動儲存為當前timestamp。

表中的第一個TIMESTAMP列,如果沒有宣告NULL屬性、DEFAULT或者 ON UPDATE,會自動分配 DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP 屬性。

表中第二個TIMESTAMP列,如果沒有宣告為NULL或者DEFAULT子句,預設自動分配’0000-00-00 00:00:00′。插入行時沒有指明改列的值,該列預設分配’0000-00-00 00:00:00′,且沒有警告。
要關閉警告,需要加入下面的引數:

explicit_defaults_for_timestamp=true

重啟MySQL後錯誤消失,這時TIMESTAMP的行為如下:

TIMESTAMP如果沒有顯示宣告NOT NULL,是允許NULL值的,可以直接設定改列為NULL,而沒有預設填充行為。
TIMESTAMP不會預設分配DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP屬性。
宣告為NOT NULL且沒有預設子句的TIMESTAMP列是沒有預設值的。往資料表中插入列,又沒有給TIMESTAMP列賦值時,如果是嚴格SQL模式,會丟擲一 個錯誤,如果嚴格SQL模式沒有啟用,該列會賦值為’0000-00-00 00:00:00′,同時出現一個警告。(這和MySQL處理其他時間型別資料一樣,如DATETIME)

也就是 explicit_defaults_for_timestamp 關閉了 timestamp 型別欄位鎖擁有的一些會讓人感到奇怪的預設行為,加入了該引數之後,如果還需要為 timestamp型別的欄位指定預設行為,那麼就需要顯示的在建立表時顯示的指定。explicit_defaults_for_timestamp 也就是這個意思:顯示指定預設值為timestamp型別的欄位。