Navicat同步时默认值写入为NULL的根本原因是源库与目标库SQL模式不一致,尤其STRICT_TRANS_TABLES缺失导致MySQL静默填NULL;必须统一sql_mode、确保字段定义含NOT NULL DEFAULT 0、清理存量NULL数据,并手动修正同步脚本中的MODIFY语句。
Navicat同步时默认值写入为NULL,先查SQL模式是否一致
navicat本身不校验两端数据库的sql_mode,但mysql在不同sql_mode下对默认值的行为差异极大——比如strict_trans_tables开启时,插入未赋值的可空字段会报错;关闭时则静默填null,哪怕你设了default 0。这直接导致“同步后字段仍是null”的假象,实际是目标库模式宽松、放行了非法插入。
检查方法很简单:
- 在源库和目标库分别执行:
SELECT @@sql_mode; - 重点比对是否都包含
STRICT_TRANS_TABLES或STRICT_ALL_TABLES - 若目标库缺失 strict 模式,即使 Navicat 同步了
NOT NULL DEFAULT 0,应用层用INSERT INTO t() VALUES()仍会写入NULL
同步前必须统一sql_mode,不能只靠Navicat改表结构
Navicat 的结构同步只操作表定义(DDL),它不会、也不能修改数据库级的sql_mode。所以即使你在源库开了 strict 模式、字段定义也正确,只要目标库sql_mode不一致,同步后的表在行为上就不可信。
实操建议:
- 生产环境目标库应全局启用
STRICT_TRANS_TABLES:在 MySQL 配置文件my.cnf中添加sql_mode = "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION",然后重启或执行SET GLOBAL sql_mode = '...';(需SUPER权限) - 不要依赖会话级设置(
SET SESSION sql_mode),Navicat 连接新建后不继承该设置 - 验证方式:连接目标库后立即执行
SELECT @@sql_mode;,确认返回值与源库完全一致,包括引号、空格、顺序
字段默认值生效还取决于NOT NULL + sql_mode双重约束
很多人以为只要在 Navicat 界面里给字段填了0作为默认值就完事了,其实 MySQL 要真正强制使用默认值,必须同时满足两个条件:字段定义为NOT NULL,且当前会话/全局sql_mode启用 strict 模式。缺一不可。
常见踩坑点:
- Navicat 界面勾选了“默认值”但漏掉“非空”,生成的 DDL 是
INT DEFAULT 0,不是INT NOT NULL DEFAULT 0 - 目标库
sql_mode含ALLOW_INVALID_DATES,会进一步弱化约束检查 - 用
mysqldump --no-data导出再导入时,如果 dump 文件里没显式写出NOT NULL,重建表后约束就丢了 - 验证字段定义是否完整:执行
SHOW CREATE TABLE `table_name`;,确认输出中对应字段行包含NOT NULL DEFAULT 0
同步脚本里别信 Navicat 自动生成的 MODIFY COLUMN 语句
Navicat 在检测到默认值变更时,常生成类似MODIFY COLUMN `status` TINYINT DEFAULT 0的语句。但它默认不带NOT NULL,也不检查原字段是否允许NULL。结果就是:目标表字段看起来“有默认值”,但实际仍可插NULL。
安全做法是手动干预同步脚本:
- 预览 Navicat 生成的 SQL 时,搜索所有
MODIFY COLUMN和CHANGE COLUMN语句 - 把其中只写
DEFAULT 0的,全部补上NOT NULL,例如改为MODIFY COLUMN `status` TINYINT NOT NULL DEFAULT 0 - 如果原字段已是
NULL,又想改成NOT NULL DEFAULT 0,必须先确保存量数据无NULL,否则ALTER TABLE会失败 - 对关键字段,宁可用两步:先
UPDATE table_name SET status = 0 WHERE status IS NULL;,再执行MODIFY变更
字段默认值是否真正生效,从来不只是 Navicat 点几下就能决定的事。它卡在sql_mode、NOT NULL、存量数据状态、同步脚本细节四个咬合点上——漏掉任意一个,都会让“设了默认值”变成一句空话。











