MySQL 5.7中explicit_defaults_for_timestamp参数
时间:2019-04-03 13:13 来源:linux.it.net.cn 作者:IT
在MySQL 5.7版本之前,且在MySQL 5.6.6版本之后(explicit_defaults_for_timestamp参数在MySQL 5.6.6开始加入)的版本中,如果没有设置explicit_defaults_for_timestamp=1的情况下:
1)在默认情况下,如果TIMESTAMP列没有显示的指明null属性,那么该列会被自动加上not null属性(而其他类型的列如果没有被显示的指定not null,那么是允许null值的),如果往这个列中插入null值,会自动的设置该列的值为current timestamp值。
2)表中的第一个TIMESTAMP列,如果没有指定null属性或者没有指定默认值,也没有指定ON UPDATE语句。那么该列会自动被加上DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性。
3)第一个TIMESTAMP列之后的其他的TIMESTAMP类型的列,如果没有指定null属性,也没有指定默认值,那么该列会被自动加上DEFAULT ‘0000-00-00 00:00:00’属性。如果insert语句中没有为该列指定值,那么该列中插入’0000-00-00 00:00:00’,并且没有warning。
在MySQL 5.6.6及以后的版本和MySQL 5.7之前的版本中,如果在配置文件中没有指定explicit_defaults_for_timestamp参数,启动时error日志中会报如下警告:
[Warning] TIMESTAMP with implicit DEFAULT value is deprecated.
Please use --explicit_defaults_for_timestamp server option (see
documentation for more details).
如果我们在启动的时候在配置文件中指定了explicit_defaults_for_timestamp=1,MySQL会按照如下的方式处理TIMESTAMP列:
1)此时如果TIMESTAMP列没有显示的指定not null属性,那么默认的该列可以为null,此时向该列中插入null值时,会直接记录null,而不是current timestamp。
2)不会自动的为表中的第一个TIMESTAMP列加上DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性,除非你在建表的时候显示的指明。
3)如果TIMESTAMP列被加上了not null属性,并且没有指定默认值。这时如果向表中插入记录,但是没有给该TIMESTAMP列指定值的时候,如果strict sql_mode被指定了,那么会直接报错。如果strict sql_mode没有被指定,那么会向该列中插入’0000-00-00 00:00:00’并且产生一个warning。
这里为什么一直强调版本呢?主要还是因为这个参数explicit_defaults_for_timestamp在MySQL 5.6.6开始加入,并且MySQL 5.6跟MySQL 5.7的默认SQL模式不同了。MySQL 5.7的SQL模式更加严格了,限制了不合法的日期输入,比如”0000-00-00 00:00:00″。详情可以看:MySQL 5.7默认SQL模式带来的问题总结。
一、启动mysql时未设置explicit_defaults_for_timestamp=1
1)创建测试表test_time
mysql> set session sql_mode='';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> create table test_time(time1 timestamp,time2 timestamp,id int);
Query OK, 0 rows affected (0.01 sec)
这里关闭了SQL模式,是因为MySQL 5.7默认SQL模式加入了NO_ZERO_DATE和NO_ZERO_IN_DATE模式,这两个模式的意思如下:
NO_ZERO_DATE
在严格模式,不要将’0000-00-00’做为合法日期。你仍然可以用IGNORE选项插入零日期。在非严格模式,可以接受该日期,但会生成警告。
NO_ZERO_IN_DATE
在严格模式,不接受月或日部分为0的日期(也就是说比NO_ZERO_DATE),对年不限制。如果使用IGNORE选项,我们为类似的日期插入’0000-00-00’。在非严格模式,可以接受该日期,但会生成警告。
所以如果不去掉这两个SQL模式,那么根据我们上面所说的表中的第一个TIMESTAMP列,如果没有指定null属性或者没有指定默认值,也没有指定ON UPDATE语句。那么该列会自动被加上DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性。第一个TIMESTAMP列之后的其他的TIMESTAMP类型的列,如果没有指定null属性,也没有指定默认值,那么该列会被自动加上DEFAULT ‘0000-00-00 00:00:00’属性。所以第二个timestamp添加默认值时就会报错的,错误如下:
mysql> create table test_time1(time1 timestamp,time2 timestamp,id int);
ERROR 1067 (42000): Invalid default value for 'time2'
表创建好了之后,下面来查看表结构信息,如下:
mysql> show create table test_time\G
*************************** 1. row ***************************
Table: test_time
Create Table: CREATE TABLE `test_time` (
`time1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`time2` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
从表结构中可以看到表中timestamp列被自动设置为not null,并且表中第一个timestamp列被设置了DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP默认值,第二个字段默认值为”0000-00-00 00:00:00″。
2)插入测试
mysql> insert into test_time select null,null,1;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from test_time;
+---------------------+---------------------+------+
| time1 | time2 | id |
+---------------------+---------------------+------+
| 2017-02-22 15:42:11 | 2017-02-22 15:42:11 | 1 |
+---------------------+---------------------+------+
1 row in set (0.00 sec)
往timestamp列插入null值时,会自动为该列设置为current time。
插入时未指定值的timestamp列中被插入了0000-00-00 00:00:00(非表中第一个timestamp列)。
mysql> select * from test_time;
+---------------------+---------------------+------+
| time1 | time2 | id |
+---------------------+---------------------+------+
| 2017-02-22 15:42:11 | 2017-02-22 15:42:11 | 1 |
| 2017-02-22 15:45:09 | 0000-00-00 00:00:00 | 1 |
+---------------------+---------------------+------+
2 rows in set (0.00 sec)
二、启动mysql时设置explicit_defaults_for_timestamp=1
1)创建表(不需要改变sql mode)
mysql> create table test_time(time1 timestamp,time2 timestamp,id int);
Query OK, 0 rows affected (0.00 sec)
mysql> show create table test_time\G
*************************** 1. row ***************************
Table: test_time
Create Table: CREATE TABLE `test_time1` (
`time1` timestamp NULL DEFAULT NULL,
`time2` timestamp NULL DEFAULT NULL,
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
通过表结构我们看到,2个timestamp列都被设置为null,并且设置了默认值为null。
2)插入测试
mysql> insert into test_time select null,1;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from test_time;
+-------+-------+------+
| time1 | time2 | id |
+-------+-------+------+
| NULL | NULL | 1 |
+-------+-------+------+
1 row in set (0.00 sec)
为timestamp列指定了not null属性,在strict SQL mode时,如果插入时该列没有指定值,会直接报错。
mysql> create table test_time(time1 timestamp,time2 timestamp not null,id int);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into test_time select null,null,1;
ERROR 1048 (23000): Column 'time2' cannot be null
如果为timestamp列指定not null属性,在非stric sql_mode模式下,如果插入的时候该列没有指定值,那么会向该列中插入0000-00-00 00:00:00,并且产生告警。
mysql> set session sql_mode='';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> insert into test_time select null,null,1;
Query OK, 1 row affected, 1 warning (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 1
mysql> show warnings;
+---------+------+-------------------------------+
| Level | Code | Message |
+---------+------+-------------------------------+
| Warning | 1048 | Column 'time2' cannot be null |
+---------+------+-------------------------------+
1 row in set (0.00 sec)
mysql> select * from test_time;
+-------+---------------------+------+
| time1 | time2 | id |
+-------+---------------------+------+
| NULL | 0000-00-00 00:00:00 | 1 |
+-------+---------------------+------+
1 row in set (0.00 sec)
上面说的都是关于timestamp类型的,如果是datetime呢?
mysql> create table time1(id int,time1 datetime,time2 datetime);
Query OK, 0 rows affected (0.03 sec)
mysql> show create table time1\G
*************************** 1. row ***************************
Table: time1
Create Table: CREATE TABLE `time1` (
`id` int(11) DEFAULT NULL,
`time1` datetime DEFAULT NULL,
`time2` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> insert into time1(id) values(1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from time1;
+------+-------+-------+
| id | time1 | time2 |
+------+-------+-------+
| 1 | NULL | NULL |
+------+-------+-------+
1 row in set (0.00 sec)
可以看到跟普通类型一样。
(责任编辑:IT)
在MySQL 5.7版本之前,且在MySQL 5.6.6版本之后(explicit_defaults_for_timestamp参数在MySQL 5.6.6开始加入)的版本中,如果没有设置explicit_defaults_for_timestamp=1的情况下: 1)在默认情况下,如果TIMESTAMP列没有显示的指明null属性,那么该列会被自动加上not null属性(而其他类型的列如果没有被显示的指定not null,那么是允许null值的),如果往这个列中插入null值,会自动的设置该列的值为current timestamp值。 2)表中的第一个TIMESTAMP列,如果没有指定null属性或者没有指定默认值,也没有指定ON UPDATE语句。那么该列会自动被加上DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性。 3)第一个TIMESTAMP列之后的其他的TIMESTAMP类型的列,如果没有指定null属性,也没有指定默认值,那么该列会被自动加上DEFAULT ‘0000-00-00 00:00:00’属性。如果insert语句中没有为该列指定值,那么该列中插入’0000-00-00 00:00:00’,并且没有warning。 在MySQL 5.6.6及以后的版本和MySQL 5.7之前的版本中,如果在配置文件中没有指定explicit_defaults_for_timestamp参数,启动时error日志中会报如下警告: [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details). 如果我们在启动的时候在配置文件中指定了explicit_defaults_for_timestamp=1,MySQL会按照如下的方式处理TIMESTAMP列: 1)此时如果TIMESTAMP列没有显示的指定not null属性,那么默认的该列可以为null,此时向该列中插入null值时,会直接记录null,而不是current timestamp。 2)不会自动的为表中的第一个TIMESTAMP列加上DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性,除非你在建表的时候显示的指明。 3)如果TIMESTAMP列被加上了not null属性,并且没有指定默认值。这时如果向表中插入记录,但是没有给该TIMESTAMP列指定值的时候,如果strict sql_mode被指定了,那么会直接报错。如果strict sql_mode没有被指定,那么会向该列中插入’0000-00-00 00:00:00’并且产生一个warning。 这里为什么一直强调版本呢?主要还是因为这个参数explicit_defaults_for_timestamp在MySQL 5.6.6开始加入,并且MySQL 5.6跟MySQL 5.7的默认SQL模式不同了。MySQL 5.7的SQL模式更加严格了,限制了不合法的日期输入,比如”0000-00-00 00:00:00″。详情可以看:MySQL 5.7默认SQL模式带来的问题总结。 一、启动mysql时未设置explicit_defaults_for_timestamp=1 1)创建测试表test_time mysql> set session sql_mode=''; Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> create table test_time(time1 timestamp,time2 timestamp,id int); Query OK, 0 rows affected (0.01 sec) 这里关闭了SQL模式,是因为MySQL 5.7默认SQL模式加入了NO_ZERO_DATE和NO_ZERO_IN_DATE模式,这两个模式的意思如下: NO_ZERO_DATE 在严格模式,不要将’0000-00-00’做为合法日期。你仍然可以用IGNORE选项插入零日期。在非严格模式,可以接受该日期,但会生成警告。 NO_ZERO_IN_DATE 在严格模式,不接受月或日部分为0的日期(也就是说比NO_ZERO_DATE),对年不限制。如果使用IGNORE选项,我们为类似的日期插入’0000-00-00’。在非严格模式,可以接受该日期,但会生成警告。 所以如果不去掉这两个SQL模式,那么根据我们上面所说的表中的第一个TIMESTAMP列,如果没有指定null属性或者没有指定默认值,也没有指定ON UPDATE语句。那么该列会自动被加上DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性。第一个TIMESTAMP列之后的其他的TIMESTAMP类型的列,如果没有指定null属性,也没有指定默认值,那么该列会被自动加上DEFAULT ‘0000-00-00 00:00:00’属性。所以第二个timestamp添加默认值时就会报错的,错误如下: mysql> create table test_time1(time1 timestamp,time2 timestamp,id int); ERROR 1067 (42000): Invalid default value for 'time2' 表创建好了之后,下面来查看表结构信息,如下: mysql> show create table test_time\G *************************** 1. row *************************** Table: test_time Create Table: CREATE TABLE `test_time` ( `time1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `time2` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `id` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 1 row in set (0.00 sec) 从表结构中可以看到表中timestamp列被自动设置为not null,并且表中第一个timestamp列被设置了DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP默认值,第二个字段默认值为”0000-00-00 00:00:00″。 2)插入测试 mysql> insert into test_time select null,null,1; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from test_time; +---------------------+---------------------+------+ | time1 | time2 | id | +---------------------+---------------------+------+ | 2017-02-22 15:42:11 | 2017-02-22 15:42:11 | 1 | +---------------------+---------------------+------+ 1 row in set (0.00 sec) 往timestamp列插入null值时,会自动为该列设置为current time。 插入时未指定值的timestamp列中被插入了0000-00-00 00:00:00(非表中第一个timestamp列)。 mysql> select * from test_time; +---------------------+---------------------+------+ | time1 | time2 | id | +---------------------+---------------------+------+ | 2017-02-22 15:42:11 | 2017-02-22 15:42:11 | 1 | | 2017-02-22 15:45:09 | 0000-00-00 00:00:00 | 1 | +---------------------+---------------------+------+ 2 rows in set (0.00 sec) 二、启动mysql时设置explicit_defaults_for_timestamp=1 1)创建表(不需要改变sql mode) mysql> create table test_time(time1 timestamp,time2 timestamp,id int); Query OK, 0 rows affected (0.00 sec)
mysql> show create table test_time\G *************************** 1. row *************************** Table: test_time Create Table: CREATE TABLE `test_time1` ( `time1` timestamp NULL DEFAULT NULL, `time2` timestamp NULL DEFAULT NULL, `id` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 1 row in set (0.00 sec) 通过表结构我们看到,2个timestamp列都被设置为null,并且设置了默认值为null。 2)插入测试 mysql> insert into test_time select null,1; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from test_time; +-------+-------+------+ | time1 | time2 | id | +-------+-------+------+ | NULL | NULL | 1 | +-------+-------+------+ 1 row in set (0.00 sec) 为timestamp列指定了not null属性,在strict SQL mode时,如果插入时该列没有指定值,会直接报错。 mysql> create table test_time(time1 timestamp,time2 timestamp not null,id int); Query OK, 0 rows affected (0.01 sec)
mysql> insert into test_time select null,null,1; ERROR 1048 (23000): Column 'time2' cannot be null 如果为timestamp列指定not null属性,在非stric sql_mode模式下,如果插入的时候该列没有指定值,那么会向该列中插入0000-00-00 00:00:00,并且产生告警。 mysql> set session sql_mode=''; Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> insert into test_time select null,null,1; Query OK, 1 row affected, 1 warning (0.00 sec) Records: 1 Duplicates: 0 Warnings: 1
mysql> show warnings; +---------+------+-------------------------------+ | Level | Code | Message | +---------+------+-------------------------------+ | Warning | 1048 | Column 'time2' cannot be null | +---------+------+-------------------------------+ 1 row in set (0.00 sec)
mysql> select * from test_time; +-------+---------------------+------+ | time1 | time2 | id | +-------+---------------------+------+ | NULL | 0000-00-00 00:00:00 | 1 | +-------+---------------------+------+ 1 row in set (0.00 sec) 上面说的都是关于timestamp类型的,如果是datetime呢? mysql> create table time1(id int,time1 datetime,time2 datetime); Query OK, 0 rows affected (0.03 sec)
mysql> show create table time1\G *************************** 1. row *************************** Table: time1 Create Table: CREATE TABLE `time1` ( `id` int(11) DEFAULT NULL, `time1` datetime DEFAULT NULL, `time2` datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
mysql> insert into time1(id) values(1); Query OK, 1 row affected (0.00 sec)
mysql> select * from time1; +------+-------+-------+ | id | time1 | time2 | +------+-------+-------+ | 1 | NULL | NULL | +------+-------+-------+ 1 row in set (0.00 sec) 可以看到跟普通类型一样。 (责任编辑:IT) |