事务中的golang sql/数据库准备语句

事务中的golang sql/数据库准备语句,go,Go,当我阅读golang SQL/数据库示例中“transaction”中“Prepared”语句的示例时。其中一行写着“危险”,但代码示例没有其他选择 我想对下面的问题有更清楚的解释,因为维基页面上没有提供太多的信息,网址是—— 我看不出上面两个代码有什么不同,但是,如果有任何不同或者我遗漏了什么,我需要专家的建议。adefer语句是一种很好的方法,可以确保无论您如何退出函数,都能运行某些东西 在这种情况下,这似乎无关紧要,因为所有错误处理程序都使用log.Fatal。如果用return语句替换l

当我阅读golang SQL/数据库示例中“transaction”中“Prepared”语句的示例时。其中一行写着“危险”,但代码示例没有其他选择

我想对下面的问题有更清楚的解释,因为维基页面上没有提供太多的信息,网址是——


我看不出上面两个代码有什么不同,但是,如果有任何不同或者我遗漏了什么,我需要专家的建议。

a
defer
语句是一种很好的方法,可以确保无论您如何退出函数,都能运行某些东西

在这种情况下,这似乎无关紧要,因为所有错误处理程序都使用
log.Fatal
。如果用
return
语句替换
log.Fatal
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
tx,err:=db.Begin()
如果出错!=零{
返回零,错误
}
stmt,err:=tx.Prepare(“插入到foo值(?))
如果出错!=零{
tx.回滚()
返回零,错误
}
推迟
对于i:=0;i<10;i++{
_,err=stmt.Exec(i)
如果错误!=零{
tx.回滚()
返回零,错误
}
}
err=tx.Commit()
如果出错!=零{
stmt.Close()
tx.回滚()
返回零,错误
}
stmt.Close()
返回someValue,nil

如果使用“延迟”,则很难忘记需要清理的某个位置。

可能是Close返回一个被忽略的错误。你的版本也有同样的问题。为了更安全地使用延迟,您可以将结束封装在func中,该func会处理错误,或者在第二个版本中返回错误并检查tx的完整性。评论说延迟在Go 1.4中是危险的,但这在很久以前就被修复了。使用log.Fatal也是不幸的。我不确定我是否会将此作为示例,相反,您可以查看sql pkg示例,尽管这些示例没有很好地涵盖准备好的语句是的,我也不会使用
fatal
。我会做类似的事情
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()
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