小编典典

事务中的golang sql / database预处理语句

go

在阅读golang SQL /数据库示例中“事务”中“准备”语句的示例时。其中一行说“危险”,但提供的代码示例没有其他选择。

我想对下面的查询有更清晰的解释,因为Wiki页面-http://go-database-sql.org/prepared.html上没有提供太多信息。

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()

我发现上面的两个代码没有什么区别,但是,如果有任何区别或缺少某些内容,我需要上面的专家建议。


阅读 226

收藏
2020-07-02

共1个答案

小编典典

一个defer说法是一个很好的方式,以确保运行的东西不管你怎么退出功能。

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

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

如果使用延迟,则很难忘记需要清理的地方。

2020-07-02