Golang:重复键值违反唯一约束

Golang: duplicate key value violates unique constraint

当我尝试将两个或更多寄存器插入for循环时出现此错误,第一个工作正常但随后出现错误,数据库是新的并且我已经重新创建了很多次

pq: duplicate key value violates unique constraint \"movements_pkey\

我有这个动作模型

type Movement struct {
    ID        int        `gorm:"primary_key" json:"id"`
    Amount    float32    `json:"amount"`
    FkType    *int       `gorm:"column:fk_type" json:"fk_type"`
    Type      Type       `gorm:"foreignkey:FkType"`
    FkIncome  int        `gorm:"column:fk_income" json:"fk_income"`
    Income    Incoming   `gorm:"foreignkey:FkIncome"`
    FkOrder   *int       `gorm:"column:fk_order" json:"fk_order,omitempty"`
    CreatedAt *time.Time `json:"created_at"`
}

这里是我在 for 循环中调用保存数据库 (MovementCreate) 的函数,第一个总是成功创建但第二个给我这个错误,尝试创建一个新记录但显然postgresql 采用相同的最后一个 id

func (w *WebServices) CreateMovementMoneyOut(dataMovement *validators.MovementValidator) ([]models.IncomingResult, error) {
    nameFile := "Movement Services"
    dataWallet, err := w.wallet.FindWalletByCustomerID(dataMovement.FKCustomer)
    if err != nil {
        utils.LogService(nameFile, "Wallet Find", err.Error(), "error")
        return nil, err
    }
    if (dataWallet.Amount <= 0) || !(*dataMovement.FkType == 2) {
        utils.LogService(nameFile, "Wallet Update", "Insufficients funds", "error")
        return nil, fmt.Errorf("Insufficients funds")
    }
    incomingUpdate, err := w.incoming.UpdateIncomingsByFkWallet(&dataWallet.ID, *dataMovement.Amount)
    var movement models.Movement
    for _, val := range incomingUpdate {
        movement.Amount = val.Amount
        movement.FkIncome = val.ID
        movement.FkType = dataMovement.FkType
        movement.FkOrder = dataMovement.FkOrder
        _, err := w.movement.MovementCreate(&movement)

        if err != nil {
            utils.LogService(nameFile, "CreateMovementMoneyOut", err.Error(), "error")
            return nil, err
        }
    }
    newAmount, err := w.incoming.CalculateWalletAmount(&dataWallet.ID)
    if err != nil {
        utils.LogService(nameFile, "Wallet Update", err.Error(), "error")
    }
    _, err = w.wallet.WalletUpdateAmount(dataWallet, newAmount)
    if err != nil {
        utils.LogService(nameFile, "Wallet Update", err.Error(), "error")
        return nil, err
    }
    return incomingUpdate, nil
}

保存到数据库时在此处

func (s *WalletService) MovementCreate(data *Movement) (*Movement, error) {
  result := s.Create(data)
  return data, result.Error
}

控制台错误的完整响应是这样的

2021/12/08 20:57:18 /usr/src/app/pkg/datalayers/models/movement.go:45 pq: duplicate key value violates unique constraint "movements_pkey"
[1.249ms] [rows:0] INSERT INTO "movements" ("amount","fk_type","fk_income","fk_order","created_at","id") VALUES (1000.000000,2,7,1,'2021-12-08 20:57:16.173',16) RETURNING "id"

16是循环中第一次迭代成功创建的最后一个id,下一次迭代尝试使用相同的id但新记录的正确数据

如果您使用的是 gorm V2,则将 primary_key 替换为 primaryKey,并添加 autoIncrement,默认情况下将为 true。如果你愿意,你可以添加 Unique 约束,这取决于你。

type Movement struct {
    ID        uint64     `gorm:"primaryKey;autoIncrement" json:"id"` //Change it
    Amount    float32    `json:"amount"`
    FkType    *int       `gorm:"column:fk_type" json:"fk_type"`
    Type      Type       `gorm:"foreignkey:FkType"`
    FkIncome  int        `gorm:"column:fk_income" json:"fk_income"`
    Income    Incoming   `gorm:"foreignkey:FkIncome"`
    FkOrder   *int       `gorm:"column:fk_order" json:"fk_order,omitempty"`
    CreatedAt *time.Time `json:"created_at"`
}

您需要为每组数据创建一个对象。在 for 循环中添加此 var movement models.Movement

而且你不需要提到 movement.ID 默认情况下它会被 gorm 很好地处理。

    for _, val := range incomingUpdate {
    var movement models.Movement             //Update it
    movement.Amount = val.Amount
    movement.FkIncome = val.ID
    movement.FkType = dataMovement.FkType
    movement.FkOrder = dataMovement.FkOrder
    _, err := w.movement.MovementCreate(&movement)

    if err != nil {
        utils.LogService(nameFile, "CreateMovementMoneyOut", err.Error(), "error")
        return nil, err
    }
}