需确保所有not null字段在insert时显式赋值或有默认值,而非依赖关闭严格模式;添加自增主键须同时设primary key和auto_increment;检查autocommit、权限及代理层策略。
insert 报错 error 1364 (hy000): field doesn't have a default value 怎么办
这是最常见表象:明明设了 id 为主键 + auto_increment,但执行 insert into table (name) values ('a') 就报这个错。根本原因不是主键没生效,而是 mysql 严格模式下,非空字段(not null)又没给值、也没默认值,就会拦住整条语句。
- 先查字段定义:
DESCRIBE table_name,确认所有NOT NULL字段是否都有默认值或在 INSERT 中显式赋值 -
id自增只解决它自己不填的问题,其他NOT NULL字段(比如created_at、status)必须处理 - 别依赖
SET SQL_MODE = ''关严格模式来绕过——这是掩耳盗铃,上线环境通常不允许,且掩盖真实数据约束问题
ALTER TABLE 添加 AUTO_INCREMENT 后 INSERT 仍失败
直接对已有表加自增主键,容易漏掉两个关键动作:设主键 + 设自增属性必须同时完成,且原数据可能冲突。
- 错误写法:
ALTER TABLE t ADD COLUMN id INT;→ALTER TABLE t MODIFY id INT AUTO_INCREMENT;→ 缺少PRIMARY KEY,MySQL 不认它是主键,自增无效 - 正确顺序:
ALTER TABLE t ADD COLUMN id INT PRIMARY KEY AUTO_INCREMENT FIRST;(注意FIRST避免因位置引发隐式类型转换问题) - 已有数据时,必须确保
id列值唯一且非空;否则加主键会失败,得先UPDATE补值或DELETE冲突行 - 如果表里已有大量数据,
AUTO_INCREMENT起始值默认从MAX(id) + 1开始,但若之前删过记录,可能撞上残留值,建议显式指定:ALTER TABLE t AUTO_INCREMENT = 1000;
事务中 INSERT 失败后数据“消失”,是不是没提交?
不是没提交,是回滚了。很多开发者以为只要没手动 COMMIT,数据就“还在那儿等你决定”,其实只要连接断开、脚本退出、或触发了隐式回滚条件(比如唯一键冲突、外键失败),未提交事务一律丢弃。
- 检查客户端是否自动开启了事务:
SELECT @@autocommit;—— 值为0表示关了自动提交,每条语句都在事务里,必须COMMIT或ROLLBACK - 用
START TRANSACTION显式开启事务后,哪怕只执行一条INSERT,不COMMIT就断开连接,数据一定不落地 - 某些 ORM(如 Django 的
atomic、SQLAlchemy 的session)也会控制事务边界,别只看 SQL 日志,得看框架层有没有真正 commit - 权限不足也可能导致“看似执行成功实则静默失败”:比如用户只有
INSERT权限但没SELECT权限,而 ORM 在插入后顺手查了一次刚插的记录做验证,这时查失败会触发回滚,但日志里只显示 SELECT 错误
用户权限不足导致 INSERT 被拒,但错误信息没提示权限问题
MySQL 默认错误码 ERROR 1142 (42000): INSERT command denied to user 是明确的,但有些情况它藏得深:比如用户有 INSERT 权限,但没权限写入对应存储引擎要求的系统表(如 InnoDB 的数据字典),或者触发器里用了无权限的表,错误就变成 ERROR 1442 (HY000): Can't update table in stored function/trigger 这类误导性提示。
- 用
SHOW GRANTS FOR 'user'@'host';看实际分配的权限,重点核对:INSERT、SELECT(很多 ORM 插完要查)、EXECUTE(如果有触发器或函数) - 权限是按库+表粒度分的,
GRANT INSERT ON db.* TO ...不等于GRANT INSERT ON db.table,尤其跨库操作时容易漏 - 如果用的是代理(如 ProxySQL、MaxScale)或云数据库(如 RDS),权限策略可能被中间层重写,得去对应控制台查实际生效策略,不能只信本地
SHOW GRANTS
自增主键和事务回滚本身不难,难的是它们总和权限、存储引擎行为、ORM 封装、代理层策略缠在一起。排查时别盯着 AUTO_INCREMENT 单点猛捶,先用 DESCRIBE、SHOW GRANTS、SELECT @@autocommit 这三句话把底子摸清,比改十次 DDL 有用得多。










