目录

gorm insert 报错 DELETE SET NULL ON UPDATE SET NULL

最近在基于 GO 开发后台项目时,用 GORM 操作 MySQL 数据库插入数据,突然抛出一串报错,核心信息直指 DELETE SET NULL ON UPDATE SET NULL

起初以为是插入语句语法问题,排查后才发现是外键约束配置的“隐形坑”。

结合多份资料和实测,整理记录下完整排错思路,分享给有同样困扰的开发者。希望对大家有所帮助

复现

先定义两张表结构如下,其中 Stu 表中的 SchId 是表的外键, 是 School 表的主键

type School struct{
       SchId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;not null;primary_key;AUTO_INCREMENT;"`
    Name      string  `json:"Name"        gorm:"column:Name;type:varchar;size:500;not null;default:'galeone'"`
}
type Stu struct{
    StuId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;not null;primary_key;AUTO_INCREMENT;"`
    Name      string  `json:"Name"        gorm:"column:Name;type:varchar;size:500;not null;"`
    SchId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;"`
}

然后在 go 中使用 gorm insert 插入数据时,出现报错如下:

func main() {
    addModel := model.Stu{
        StuId: 1111,
        Name:   "******",
    }
    err:=dao.insert(&addModel)
    if err.Error!=nil{
        fmt.Println(err)
    }
}
Error 1452: Cannot add or update a child row: a foreign key constraint fails 
(`ew_nfdas`.`stu`, CONSTRAINT `fk_stud_schid` FOREIGN KEY (`SchId`) REFERENCES `school` (`SchId`) ON DELETE SET NULL ON UPDATE SET NULL) 

插入语句:

INSERT INTO stu (StuId,Name,SchId) VALUES (1111,’******’,0)

由于 SchId 为外键,0 值插入报错不存在,关联的 School 表 没有主键=0 的数据

正确的 sql 应该是:

INSERT INTO stu (StuId,Name) VALUES (1111,’******')

根本原因

这是因为 gorm 生成的 insert 语句存在问题(或者说存在适配问题):

INSERT INTO `stu` (`StuId`,`Name`,`SchId`) VALUES (1111,'******',0)

但是由于 SchId 为外键,0 值插入报错不存在,关联的 School 表 没有主键=0 的数据

此时数据库表没有设置外键约束,是可以为 null,因此正确的 sql 语句应该是:

INSERT INTO `stu` (`StuId`,`Name`) VALUES (1111,'******')

解决

那么知道原因之后,解决方法也比较简单,有多种方式

(一)设置默认值

既然 0 值不存在,那么就设置一个存在的值不就可以了…

只需要给字段设置默认值即可,也就是当字段是类型零值(0,’’,false)时,会自动使用默认值替换

比如

 SchId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;default:1"`

当 SchID 的值为零值 0 时,gorm 会自动用 1 替换,前提条件是 School 表需要有一条主键=1 的数据,才不会出现报错

(二)设置默认值为缺省

这种方法就是修正 gorm 生成的 sql 语句,零值字段就不生成在 sql 语句里了

用 default:“galeone” 设置默认值为缺省 ,如下:

 SchId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;galeone:"`

当 SchID 的值为零值 0 时,gorm 会忽略该字段作为 sql 的条件

比如前面的语句就会变成(该字段被忽略):

INSERT INTO `stu` (`StuId`,`Name`) VALUES (1111,'******')

(三)设置指针类型

还可以将类型设置为指针类型,也可以解决 ,本质和方法二一致,都是修正 gorm 生成的 sql 语句

常见问题

Q1:外键字段改为 *int 后,插入时能传 NULL 吗?

可以。

如果业务允许“未关联用户的订单”,插入时将 UserID 设为 nil 即可。例如:

order := Order{
    OrderNo: "ORD20251204002",
    Amount:  59.99,
    UserID:  nil, // 未关联用户
}

Q2:报错后先删约束再插入可行吗?

不建议。

外键约束是保证数据一致性的重要手段,删除约束可能导致脏数据。

正确做法是让字段属性适配约束,而非删除约束。

总结

这次 GORM INSERT 报错的核心是“外键约束配置与字段属性不匹配”,看似复杂的报错信息,根源却在基础的模型定义细节。

遇到数据库关联类报错时,优先检查约束与字段属性的匹配性,往往能快速定位问题。

如果还有其他排错技巧,欢迎在评论区补充交流。

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/go-gorm-err-2/

备用原文链接: https://blog.fiveyoboy.com/articles/go-gorm-err-2/