我正在编写一个 Go 应用程序,它应该将文件中的数千个值插入到数据库中。这工作正常,只要所有值都可以插入到数据库中。如果其中一个查询失败,之后所有查询都会失败,因为 pq::当前事务被中止,命令被忽略直到事务 block 结束
我想插入所有元素,如果一个元素插入失败,应该跳过它,插入其他元素。
我的代码:
func (db *Database) Insert(values []Value) (transerr error) {
tx, err := db.Begin()
if transerr != nil {
return nil, err
}
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}
stmt, err := tx.Prepare("INSERT INTO foo VALUES (?)")
if err != nil {
return err
}
defer stmt.Close()
for _, value : range values {
_, err = stmt.Exec(value)
if err != nil {
log.Error(err)
}
}
return nil
}
我尝试添加一个 tx.Rollback() 以防 stmt.Exec 失败 - 但这会导致 sql: statement is closed
。
最佳答案
对于 Postgresql,您可以使用ON CONFLICT DO NOTHING
我已经在我这边用 postgresql db 尝试了下面的代码,它忽略了有错误的插入行。我做了一些其他的改变来尝试在我这边。您可以忽略我的其他更改。
func insert(db *sql.DB, values []string) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Commit()
stmt, err := tx.Prepare("INSERT INTO foo ( foo_col) VALUES ($1) ON CONFLICT DO NOTHING")
if err != nil {
fmt.Println("errro at stmt", err)
return err
}
defer stmt.Close()
for _, value := range values {
_, err = stmt.Exec(value)
if err != nil {
fmt.Println(value, err)
}
}
return nil
}
对于mysql,可以使用INSERT IGNORE
stmt, err := tx.Prepare("INSERT IGNORE INTO foo ( foo_col) VALUES ($1) ")
关于golang 数据库事务 : continue if single exec statement fails,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52345294/