为了账号安全,请及时绑定邮箱和手机立即绑定

防止 GORM 在一个重复的主键错误后放弃 INSERT

防止 GORM 在一个重复的主键错误后放弃 INSERT

Go
一只甜甜圈 2023-02-14 15:42:06
我从 API 中提取数据。拉取结果生成结构数组,每个数组包含 100 个元素。我用来将它们插入数据库的代码是:   func (ACUpdater) InsertToTable(rawData *models.Contacts, table *gorm.DB) {    for i := 0; i < len(rawData.Results); i++ {        temp := models.ACQ_report{            ID :                           "",  //to be created later by hashing below data fields            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)        table.Create(&temp)        fmt.Println(&temp)        fmt.Println(i)    }}我使用数据字段的散列作为表的主键,因此如果这些数据字段中的任何一个发生变化,散列也会发生变化。这样,我就可以将已更改的记录附加到现有表中,而不必担心重复的主键。INSERTING问题是,在 GORM 出现 1 个重复主键错误后,上述功能完全“放弃” 。如果要插入数据库的第一条记录是重复的,那么tx.Created(&temp)仍然会运行,但不会插入更改的记录。好像tx.Create()在第一个重复的主键错误之后放弃了。如何修复此行为?
查看完整描述

1 回答

?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

这里的第一个问题可能掩盖了实际的根本原因,即您没有检查是否INSERT返回错误。你会这样做:


result := tx.Create(&temp)

if result.Error != nil {

  // handle it somehow

}

如果你这样做并检查错误,你可能会看到一些东西:


错误:重复键值违反唯一约束

即使您还看到以下错误,您也可能会看到这一点。在这种情况下,您的 INSERT 正在执行,但失败了。如果您没有看到任何其他错误并且只打印一次,那么您可能传入了一个 gorm.DB 句柄,该句柄已链接到数据库会话,并且会在第一个错误时失败。


例如,如评论中所述,如果将结果传递db.Table("my_table")给此方法,则将出现上述情况。要修复它,只需传递db或db.NewSession(),并更新您的方法以指定表(或模型,更像 Gorm):


result := db.Table("my_table_name").Create(&temp)

if result.Error != nil {

  // ...

}

选项 2:错误:当前事务被中止,命令被忽略,直到事务块结束

如果您看到这一点,则意味着您的方法正在事务中运行它的插入。这对你来说并非如此,但由于这是一个通用论坛,我将在此处留下这个和下面的解释:在 Postgres 中,如果任何语句在事务中失败,你不能执行任何进一步的语句,除了 ROLLBACK .

要解决此问题,您有几种选择:

  1. 在尝试插入之前进行更多的数据验证,直到您可以可靠地预期每次插入都会成功。您还可以使用 Gorm 的批量插入功能通过这种方法优化插入。

  2. 不要使用事务。如果您可以接受跳过的行,并且不担心重复,那么这是一个合理的选择。

  3. 使用保存点。在 Postgres 中,SAVEPOINT 类似于事务中的检查点,您可以回滚到它而不是回滚整个事务,这正是您想要的:

tx.SavePoint("sp1")            // SAVEPOINT sp1;

result := tx.Create(&temp)

if result.Error != nil {

  tx.RollbackTo("sp1")         // ROLLBACK TO sp1;

}


查看完整回答
反对 回复 2023-02-14
  • 1 回答
  • 0 关注
  • 409 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信