mysql字段默认值仅在insert时完全省略该字段或显式写default才生效,不参与update,且受sql mode、类型、版本等多重限制。
☞☞☞☞点击夸克ai手把手教你,操作像呼吸一样简单!☜☜☜☜☜

MySQL 字段默认值只在 INSERT 语句中**完全省略该字段**或**显式写 DEFAULT** 时才生效;它不是 ORM 层的兜底逻辑,也不参与 UPDATE(除非你手动写 SET col = DEFAULT)。
CREATE TABLE 时设默认值:引号、类型、函数要对齐
建表是设置默认值最干净的时机,但细节错一个就报错:
- 字符串必须加单引号:
status VARCHAR(20) DEFAULT 'inactive',写成DEFAULT inactive会被当列名处理 - 数值不加引号:
score TINYINT DEFAULT 0,DEFAULT '0'可能触发隐式转换,存成 0 但类型不稳 -
CURRENT_TIMESTAMP不能带括号:created_at DATETIME DEFAULT CURRENT_TIMESTAMP✅,CURRENT_TIMESTAMP()❌ - 字段定义了
NOT NULL却没写DEFAULT,且 SQL mode 含STRICT_TRANS_TABLES,插入时省略该字段必报错:Field 'xxx' doesn't have a default value -
TEXT/BLOB在 MySQL 8.0.19 之前不支持DEFAULT,哪怕写DEFAULT ''也会被拒绝
ALTER TABLE 修改默认值:版本决定语法,MODIFY 要重写整列
已有表加默认值,不能只写半条命令——旧版和新版语法差异大:
- MySQL 8.0.13+ 推荐用独立语法:
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'pending' - MySQL 5.7 或兼容性要求高时,必须用
MODIFY COLUMN:ALTER TABLE users MODIFY COLUMN status VARCHAR(20) DEFAULT 'pending'—— 注意:这里必须完整写出类型、长度、约束(比如漏掉NOT NULL就会把非空删了) - 想删默认值,用
DROP DEFAULT:ALTER TABLE users ALTER COLUMN email DROP DEFAULT;别写DEFAULT NULL,那仍是默认值,且对NOT NULL字段直接冲突 - 执行后**不影响已有数据**,只作用于后续未显式赋值的
INSERT
DEFAULT CURRENT_TIMESTAMP 的坑:版本、类型、SQL mode 全要卡准
想让 DATETIME 字段自动填当前时间,光写 DEFAULT CURRENT_TIMESTAMP 不够:
-
DATETIME支持该语法仅从 MySQL 5.6.5+ 开始;低于此版本会报错或静默转成'0000-00-00 00:00:00' -
ON UPDATE CURRENT_TIMESTAMP对DATETIME仅在 8.0.19+ 支持;老版本只能靠TIMESTAMP实现双时间戳 - 执行
ALTER TABLE ... MODIFY COLUMN ts DATETIME DEFAULT CURRENT_TIMESTAMP报Invalid default value for 'ts'?大概率是 SQL mode 含NO_ZERO_DATE,且表里已有非法时间值(如'0000-00-00'),得先清理脏数据或临时调低限制 -
JSON类型字段不能设DEFAULT ''(2026 年资料确认)
INSERT 时不触发默认值?先查这三件事
写了 DEFAULT 却发现字段还是 NULL 或报错,通常不是语法问题,而是环境或理解偏差:
- 客户端驱动(如 PyMySQL、JDBC)把空字符串
''自动转成NULL,而字段又是NOT NULL,导致绕过默认值逻辑 - SQL mode 含
STRICT_ALL_TABLES时,即使字段允许NULL,插入NULL值也会被拒绝(而非退而使用默认值) - 误以为
UPDATE会触发默认值 —— 不会。DEFAULT仅对INSERT生效;UPDATE t SET updated_at = DEFAULT才强制重置为默认值
真正容易被忽略的是:默认值只是 INSERT 时的“字段级填充开关”,它不感知业务逻辑、不校验上下文、不修改存量数据。哪怕你设了 DEFAULT CURRENT_TIMESTAMP,只要某次 INSERT 显式传了 NULL 或空字符串,它就彻底不介入。











