MySQL 的 DEFAULT 约束在数据库层面生效,INSERT 时省略字段才触发默认值;PHP 不自动填充,传 NULL 会绕过 DEFAULT;DATETIME 与 TIMESTAMP 默认行为不同,需注意严格模式一致性。

MySQL 表结构里用 DEFAULT 设置字段默认值
PHP 本身不提供“新增数据时自动填默认值”的机制,真正起作用的是数据库层面的 DEFAULT 约束。只要你在建表或修改表时为字段指定了 DEFAULT,INSERT 语句中省略该字段,MySQL 就会自动填入默认值。
常见错误是只在 PHP 数组里设个 $data['status'] = 'active',但没在数据库加约束——这样一旦绕过 PHP(比如直接 SQL 插入、CLI 脚本、其他语言调用),默认逻辑就失效了。
-
DEFAULT值必须是常量:比如'pending'、0、CURRENT_TIMESTAMP;不能是函数调用如NOW()(MySQL 5.6.5+ 允许CURRENT_TIMESTAMP,但NOW()仍非法) - 对
NOT NULL字段设DEFAULT很关键,否则 INSERT 时漏掉它会报错Field 'xxx' doesn't have a default value - 修改已有表加默认值:
ALTER TABLE users ADD COLUMN role VARCHAR(20) DEFAULT 'user';
或修改已有字段:ALTER TABLE users ALTER COLUMN status SET DEFAULT 'draft';
PHP 插入时显式传 NULL 会绕过 DEFAULT
很多人以为只要字段有 DEFAULT,INSERT 时传 NULL 也会触发默认值,其实不会。MySQL 把 NULL 当作一个明确值来处理,哪怕字段允许 NULL,也不会回退到 DEFAULT。
例如字段定义为 level TINYINT DEFAULT 1:
立即学习“PHP免费学习笔记(深入)”;
-
INSERT INTO users (name) VALUES ('Alice');→level自动为1 -
INSERT INTO users (name, level) VALUES ('Bob', NULL);→level存的是NULL,不是1 - 想让 PHP 安全地“跳过”字段,就得彻底不传它,而不是传
null或空字符串
PHP 层做兜底:用 array_merge() 补默认值
当业务逻辑复杂、字段默认值可能随条件变化(比如不同用户角色初始权限不同),或者你无法修改数据库结构时,可以在 PHP 插入前统一补值。
注意别用 array_merge(['status' => 'draft'], $input) —— 这会强制覆盖 $input 里的同名键。正确做法是只补缺失的键:
$defaults = ['status' => 'draft', 'created_at' => date('Y-m-d H:i:s')];
$data = array_merge($defaults, array_filter($input, function($v) { return $v !== null && $v !== ''; }));
更稳妥的方式是白名单过滤 + 显式赋值:
$allowed = ['name', 'email', 'status', 'role'];
$data = [];
foreach ($allowed as $field) {
$data[$field] = $input[$field] ?? ($defaults[$field] ?? null);
}
datetime 和 timestamp 字段的默认行为差异
这两个类型设 DEFAULT CURRENT_TIMESTAMP 表现不同,容易踩坑:
-
TIMESTAMP字段支持DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,一条语句搞定创建和更新时间 -
DATETIME在 MySQL 5.6.5+ 才支持CURRENT_TIMESTAMP作为默认值,且不支持ON UPDATE(除非用触发器) - PHP 中用
date('Y-m-d H:i:s')生成时间再插入,会丢失时区上下文;不如交给数据库用CURRENT_TIMESTAMP更可靠 - 如果字段是
DATETIME且没设默认值,又没在 PHP 中传值,MySQL 5.7+ 严格模式下会报错Invalid default value for 'created_at'
DEFAULT 不生效或报错不一致**。上线前务必确认 sql_mode 配置统一。











