解决GORM遇主键重复错误后终止INSERT操作的问题
问题修复方案
问题根源
GORM的*gorm.DB实例触发错误后会保留错误状态,后续所有基于该实例的数据库操作都会直接返回错误,不会实际执行SQL语句——这就是第一条主键重复后,后续插入全部终止的原因。
修复方案
方案1:使用独立会话执行单次插入
每次插入时创建独立的GORM会话,避免错误污染全局DB实例,同时可单独处理每条记录的插入错误:
func (ACUpdater) InsertToTable(rawData *models.Contacts, table *gorm.DB) { for i := 0; i < len(rawData.Results); i++ { temp := models.ACQ_report{ ID: "", // 后续通过哈希生成主键 RecordID: rawData.Results[i].ID, FirstName: rawData.Results[i].Properties.Firstname, LastName: rawData.Results[i].Properties.Lastname, Email: rawData.Results[i].Properties.Email, PhoneNumber: rawData.Results[i].Properties.Phone, ContactOwner: rawData.Results[i].Properties.HubspotOwnerID, CompanyName: rawData.Results[i].Properties.Company, } temp.ID = hashContactRecord(&temp) // 创建独立会话执行插入,隔离错误状态 result := table.Session(&gorm.Session{}).Create(&temp) if result.Error != nil { fmt.Printf("第%d条记录插入失败: %v\n", i, result.Error) } else { fmt.Println(&temp) fmt.Println(i) } } }
方案2:用ON CONFLICT直接跳过重复记录
如果不需要处理重复错误,仅希望跳过重复记录继续执行后续插入,可利用数据库冲突处理语法,通过GORM的Clauses实现:
import "gorm.io/gorm/clause" func (ACUpdater) InsertToTable(rawData *models.Contacts, table *gorm.DB) { for i := 0; i < len(rawData.Results); i++ { temp := models.ACQ_report{ ID: "", // 后续通过哈希生成主键 RecordID: rawData.Results[i].ID, FirstName: rawData.Results[i].Properties.Firstname, LastName: rawData.Results[i].Properties.Lastname, Email: rawData.Results[i].Properties.Email, PhoneNumber: rawData.Results[i].Properties.Phone, ContactOwner: rawData.Results[i].Properties.HubspotOwnerID, CompanyName: rawData.Results[i].Properties.Company, } temp.ID = hashContactRecord(&temp) // 遇到主键冲突时直接跳过,不抛出错误 result := table.Clauses(clause.OnConflict{DoNothing: true}).Create(&temp) if result.RowsAffected > 0 { fmt.Println(&temp) fmt.Println(i) } else { fmt.Printf("第%d条记录已存在,跳过插入\n", i) } } }
方案选择
- 方案1适合需要精准追踪每条记录插入状态、单独处理错误的场景;
- 方案2更简洁,适合仅需跳过重复记录、无需额外错误处理的场景。
内容的提问来源于stack exchange,提问作者Mike Abbey
相关产品推荐
相关产品推荐

