explicit_defaults_for_timestamp 是所有版本的 OceanBase 集群上均存在的一个租户变量,该变量用于指定 timestamp 数据类型在处理默认值和空值时是否启用非标准 SQL 行为。在所有版本的 OceanBase 数据库上该租户变量的默认值均为 ON,且该变量仅对 OceanBase 数据库 MySQL 模式生效,在 OceanBase 数据库 Oracle 模式中不实际生效。
详细说明
参数说明
-- 在 OceanBase 数据库 MySQL 模式的租户中
MySQL [test]> show variables like 'explicit_defaults_for_timestamp';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| explicit_defaults_for_timestamp | ON |
+---------------------------------+-------+
1 row in set (0.001 sec)
MySQL [test]> select * from information_schema.global_variables where variable_name='explicit_defaults_for_timestamp';
+---------------------------------+----------------+
| VARIABLE_NAME | VARIABLE_VALUE |
+---------------------------------+----------------+
| explicit_defaults_for_timestamp | ON |
+---------------------------------+----------------+
1 row in set (0.001 sec)
| 属性 | 描述 |
|---|---|
| 参数类型 | bool |
| 默认值 | ON |
| 取值范围 | OFF:不启用 ON:启用 |
| 生效范围 | GLOBAL SESSION |
| 是否参与序列化 | 是 |
| 是否影响计划生成 | 是 |
开启、关闭方法
开启方法:
-- 在当前 session 上开启该功能
set explicit_defaults_for_timestamp=ON;
set explicit_defaults_for_timestamp=1;
set session explicit_defaults_for_timestamp=on;
set session explicit_defaults_for_timestamp=1;
set @@explicit_defaults_for_timestamp=on;
set @@explicit_defaults_for_timestamp=1;
set @@session.explicit_defaults_for_timestamp=ON;
set @@session.explicit_defaults_for_timestamp=1;
-- 在全局级别开启该功能
set global explicit_defaults_for_timestamp=ON;
set global explicit_defaults_for_timestamp=1;
set @@global.explicit_defaults_for_timestamp=on;
set @@global.explicit_defaults_for_timestamp=1;
关闭方法:
-- 在当前 session 上关闭该功能
set explicit_defaults_for_timestamp=OFF;
set explicit_defaults_for_timestamp=0;
set session explicit_defaults_for_timestamp=off;
set session explicit_defaults_for_timestamp=0;
set @@explicit_defaults_for_timestamp=off;
set @@explicit_defaults_for_timestamp=0;
set @@session.explicit_defaults_for_timestamp=OFF;
set @@session.explicit_defaults_for_timestamp=0;
-- 在全局级别关闭该功能
set global explicit_defaults_for_timestamp=OFF;
set global explicit_defaults_for_timestamp=0;
set @@global.explicit_defaults_for_timestamp=off;
set @@global.explicit_defaults_for_timestamp=0;
主要作用
explicit_defaults_for_timestamp 变量的主要作用如下:
当
explicit_defaults_for_timestamp=OFF。非标准行为生效:
若未显式指定
NULL或NOT NULL,TIMESTAMP列会被隐式设为NOT NULL。第一个
TIMESTAMP列会自动添加DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性(除非显式覆盖)。插入
NULL到TIMESTAMP列时,可能会被替换为当前时间戳。
当 explicit_defaults_for_timestamp=ON。
遵循标准 SQL 行为:
TIMESTAMP列的默认值不会自动设置,需显式定义。允许
TIMESTAMP列接受NULL(除非显式指定NOT NULL)。
测试如下:
如果 explicit_defaults_for_timestamp=OFF:
如果
TIMESTAMP列没有显示的指明NULL属性,那么该列会被自动加上NOT NULL属性(而其他类型的列如果没有被显示的指定 NOT NULL,那么是允许 NULL 值的)。表中的第一个
TIMESTAMP列,如果没有指定NULL属性或者没有指定默认值,也没有指定ON UPDATE语句。那么该列会自动被加上DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性。第一个
TIMESTAMP列之后的其他的TIMESTAMP类型的列,如果没有指定NULL属性,也没有指定默认值,那么该列会被自动加上DEFAULT '0000-00-00 00:00:00'属性。如果INSERT语句中没有为该列指定值,那么该列中自动插入'0000-00-00 00:00:00'。
MySQL [test]> show variables like 'explicit_defaults_for_timestamp';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| explicit_defaults_for_timestamp | OFF |
+---------------------------------+-------+
1 row in set (0.001 sec)
MySQL [test]> create table test_table (
c1 timestamp,
c2 timestamp,
c3 timestamp default '2010-01-01 00:00:00'
);
Query OK, 0 rows affected (0.134 sec)
MySQL [test]> show create table test_table\G
*************************** 1. row ***************************
Table: test_table
Create Table: CREATE TABLE `test_table` (
`c1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`c2` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`c3` timestamp NOT NULL DEFAULT '2010-01-01 00:00:00'
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0
1 row in set (0.015 sec)
如果 explicit_defaults_for_timestamp=ON,则 timestamp 列上的 NULL 值不会被自动替换为当前时间戳;如果 explicit_defaults_for_timestamp=OFF,则 timestamp 列上的 NULL 值会被自动替换为当前时间戳:
MySQL [test]> create table test_table (id int, c1 timestamp not null default current_timestamp);
Query OK, 0 rows affected (0.102 sec)
MySQL [test]> show variables like 'explicit_defaults_for_timestamp';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| explicit_defaults_for_timestamp | ON |
+---------------------------------+-------+
1 row in set (0.004 sec)
MySQL [test]> insert into test_table(id) values (1);
Query OK, 1 row affected (0.019 sec)
MySQL [test]> select * from test_table;
+------+---------------------+
| id | c1 |
+------+---------------------+
| 1 | 2025-03-31 16:05:23 |
+------+---------------------+
1 row in set (0.013 sec)
MySQL [test]> insert into test_table(id,c1) values (2,null);
ERROR 1048 (23000): Column 'c1' cannot be null
MySQL [test]> set explicit_defaults_for_timestamp=OFF;
Query OK, 0 rows affected (0.000 sec)
MySQL [test]> insert into test_table(id,c1) values (2,null);
Query OK, 1 row affected (0.005 sec)
MySQL [test]> select * from test_table;
+------+---------------------+
| id | c1 |
+------+---------------------+
| 1 | 2025-03-31 16:05:23 |
| 2 | 2025-03-31 16:05:41 |
+------+---------------------+
2 rows in set (0.003 sec)
最佳实践
在实际应用中,explicit_defaults_for_timestamp 变量的选择取决于具体的业务需求和场景。如果希望 OceanBase 数据库 MySQL 能够自动为 TIMESTAMP 列赋值,并且能够接受由并发更新导致的潜在问题,那么可以将该变量设置为 OFF。然而,如果你希望 TIMESTAMP 列的行为更加明确和可预测,并且希望避免由于自动赋值导致的问题,那么建议将该变量保持默认值 ON 不变。
无论选择哪种设置,都应该在创建或修改表时明确指定 TIMESTAMP 列的默认值或使用 ON UPDATE CURRENT_TIMESTAMP 子句来显式控制其行为。这样可以确保数据的完整性和一致性,并减少潜在的问题和错误。
适用版本
OceanBase 数据库所有版本。
备注
在原生 MySQL 5.7 及更低版本上该变量默认值为 OFF,详情参见:MySQL 5.7 explicit_defaults_for_timestamp。
在原生 MySQL 8.0 及更高版本上该变量默认值为 ON,详情参见:MySQL 8.0 explicit_defaults_for_timestamp。