You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:15:43