【问题标题】:Bulk insert with Golang and Gorm deadlock in concurrency goroutines在并发 goroutine 中使用 Golang 和 Gorm 死锁进行批量插入
【发布时间】:2022-08-16 09:11:19
【问题描述】:

我正在尝试使用Gorm、Golang 和 MySQL 批量插入许多记录。我的代码如下所示:

package main

import (
    \"fmt\"
    \"sync\"

    \"gorm.io/driver/mysql\"
    \"gorm.io/gorm\"
)

type Article struct {
    gorm.Model
    Code string `gorm:\"size:255;uniqueIndex\"`
}

func main() {
    db, err := gorm.Open(mysql.Open(\"root@tcp(127.0.0.1:3306)/q_test\"), nil)
    if err != nil {
        panic(err)
    }

    db.AutoMigrate(&Article{})

    // err = db.Exec(\"TRUNCATE articles\").Error
    err = db.Exec(\"DELETE FROM articles\").Error
    if err != nil {
        panic(err)
    }

    // Build some articles
    n := 10000
    var articles []Article
    for i := 0; i < n; i++ {
        article := Article{Code: fmt.Sprintf(\"code_%d\", i)}
        articles = append(articles, article)
    }

    // // Save articles
    // err = db.Create(&articles).Error
    // if err != nil {
    //  panic(err)
    // }

    // Save articles with goroutines
    chunkSize := 100
    var wg sync.WaitGroup
    wg.Add(n / chunkSize)
    for i := 0; i < n; i += chunkSize {
        go func(i int) {
            defer wg.Done()
            chunk := articles[i:(i + chunkSize)]
            err := db.Create(&chunk).Error
            if err != nil {
                panic(err)
            }
        }(i)
    }
    wg.Wait()
}

当我运行这段代码有时(大约三分之一)我得到这个错误:

panic: Error 1213: Deadlock found when trying to get lock; try restarting transaction

如果我在没有 goroutines(注释行)的情况下运行代码,我不会遇到死锁。另外,我注意到如果我删除 code 字段上的唯一索引,死锁就不会再发生了。如果我用TRUNCATE articles 替换DELETE FROM articles 语句,死锁似乎不再发生。 我也用 Postgresql 运行了相同的代码,它可以工作,没有死锁。

知道为什么死锁只发生在 MySQL 上的唯一索引以及如何避免它?

标签: mysql go deadlock bulkinsert go-gorm


【解决方案1】:
  • DELETE 语句使用行锁执行,表中的每一行都被锁定以进行删除。
  • TRUNCATE TABLE 始终锁定表和页,但不锁定每一行。

来源:https://stackoverflow.com/a/20559931/18012302

我认为mysql需要时间来做DELETE查询。

尝试在查询删除后添加time.Sleep

    err = db.Exec("DELETE FROM articles").Error
    if err != nil {
        panic(err)
    }
    time.Sleep(time.Second)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-20
    • 2020-11-27
    • 1970-01-01
    • 2018-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    相关资源
    最近更新 更多