golang sql / database在事务中编写语句

时间:2017-09-28 18:52:57

标签: go

当我在golang SQL /数据库示例中的“transaction”中读取“Prepared”语句的示例时。其中一条线说“危险”,但代码示例是在没有替代方案的情况下提供的。

我希望对下面的查询有更清晰的解释,因为在[@ 3}}

上的Wiki页面上没有提供太多信息。
tx, err := db.Begin()
if err != nil {
    log.Fatal(err)
}
defer tx.Rollback()
stmt, err := tx.Prepare("INSERT INTO foo VALUES (?)")
if err != nil {
    log.Fatal(err)
}
defer stmt.Close() // danger!
for i := 0; i < 10; i++ {
    _, err = stmt.Exec(i)
    if err != nil {
        log.Fatal(err)
    }
}
err = tx.Commit()
if err != nil {
    log.Fatal(err)
}
// stmt.Close() runs here!

如果您在defer stmt.Close()中看到它提到,那么它很危险,但没有注释掉用户将其删除。

虽然我在上面的代码中没有看到任何问题,因为“defer”将在最后运行代码,但它们是否意味着,上面的代码是错误的,它应该替换为下面的代码或其他更好的替代代码

tx, err := db.Begin()
if err != nil {
    log.Fatal(err)
}
defer tx.Rollback()
stmt, err := tx.Prepare("INSERT INTO foo VALUES (?)")
if err != nil {
    log.Fatal(err)
}
// Commented out below line.
// defer stmt.Close()
for i := 0; i < 10; i++ {
    _, err = stmt.Exec(i)
    if err != nil {
        log.Fatal(err)
    }
}
err = tx.Commit()
if err != nil {
    log.Fatal(err)
}
// Comment removed from below line to close the stmt
stmt.Close()

我认为上述两个代码没有区别,但是,如果存在任何差异或者我遗失了某些内容,我需要上述专家建议。

1 个答案:

答案 0 :(得分:1)

defer语句是确保某些内容运行的好方法,无论您如何退出该函数。

在这种特殊情况下,似乎并不重要,因为所有错误处理程序都使用log.Fatal。如果用log.Fatal语句替换return并删除延迟,则现在必须在许多地方进行清理:

tx, err := db.Begin()
if err != nil {
    return nil,err
}
stmt, err := tx.Prepare("INSERT INTO foo VALUES (?)")
if err != nil {
    tx.Rollback()
    return nil,err
}
defer 
for i := 0; i < 10; i++ {
    _, err = stmt.Exec(i)
    if err != nil {
        tx.Rollback()
        return nil,err
    }
}
err = tx.Commit()
if err != nil {
    stmt.Close()
    tx.Rollback()
    return nil,err
}
stmt.Close()
return someValue, nil

如果您使用延迟,则更难忘记一个需要清理的地方。