报错ERROR 1138或1265的根本原因是字段存在NULL值,必须先用UPDATE填充(如字符串设''、数字设0),再执行MODIFY;MODIFY与CHANGE均可加NOT NULL但语义不同,且均会锁表。

ALTER TABLE MODIFY 报错 ERROR 1138 或 1265 怎么办
直接执行 ALTER TABLE t MODIFY name VARCHAR(50) NOT NULL 几乎必然失败,错误通常是 ERROR 1138: Invalid use of NULL value 或 ERROR 1265 (01000): Data truncated for column 'name' at row X。这不是语法问题,而是 MySQL 在加约束前会强制扫描全表验证——只要存在任意一个 NULL 值,就拒绝操作。
必须先清理数据,再加约束:
- 字符串列:用
UPDATE t SET name = '' WHERE name IS NULL(注意空字符串''≠NULL) - 数字列:用
UPDATE t SET age = 0 WHERE age IS NULL(确保类型兼容,避免隐式转换) - 日期列:用
UPDATE t SET created_at = '1970-01-01' WHERE created_at IS NULL - 清理后务必验证:
SELECT COUNT(*) FROM t WHERE name IS NULL结果必须为0
MODIFY 和 CHANGE 都能加 NOT NULL,但别用错
两者语义不同,选错会导致白忙活或语法报错:
-
MODIFY只改类型和约束,不改列名,适合纯加约束:ALTER TABLE t MODIFY name VARCHAR(50) NOT NULL -
CHANGE必须写两次列名(旧名、新名),适合重命名+加约束:ALTER TABLE t CHANGE old_name new_name VARCHAR(50) NOT NULL - 误用
CHANGE漏写新列名 →ERROR 1064;漏写NOT NULL→ 表面成功,实际没加约束 - 无论 MODIFY 还是 CHANGE,都会对整表加 SNW 锁,大表操作务必避开高峰期,在从库预演
千万级表不能“在线”加 NOT NULL,别信 ALGORITHM=INPLACE
MySQL 官方文档明确:对已有列添加 NOT NULL 约束,即使指定 ALGORITHM=INPLACE, LOCK=NONE,也会被拒绝并提示 LOCK=NONE is not supported。原因很实在——它必须逐行检查是否为 NULL,这个过程无法绕过全表扫描和锁。
可行路径只有两条:
- 业务侧提前清洗数据 + 停写窗口内执行
MODIFY(最常用) - 用
pt-online-schema-change工具做无锁变更(适合不能停写的场景,但要额外部署和测试) - 新增列替代(如加
name_new VARCHAR(50) NOT NULL DEFAULT '',再迁移数据,最后删旧列)——复杂度高,仅当其他方式不可行时考虑
加完 NOT NULL 后应用 INSERT/UPDATE 报错怎么办
约束生效后,所有写入都必须显式提供非 NULL 值。最容易忽略的不是语法,而是逻辑遗漏:
-
INSERT INTO t() VALUES()这种空字段列表,若目标列无默认值,直接触发ERROR 1364: Field 'xxx' doesn't have a default value -
INSERT INTO t SELECT ...中漏掉该列,效果等同于插入NULL -
UPDATE t SET status = NULL—— 即使该列有默认值,设为NULL仍被拒绝 - ORM(如 MyBatis、Hibernate)可能按实体字段自动生成 SQL,若实体属性为 null,生成的 SQL 就含
= NULL,需检查映射配置或手动指定字段列表
补救不一定要回退约束:给列加 DEFAULT(如 DEFAULT '')就能让省略字段的 INSERT 自动填充,NOT NULL 和 DEFAULT 完全正交,可共存。


















