当我在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()
我认为上述两个代码没有区别,但是,如果存在任何差异或者我遗失了某些内容,我需要上述专家建议。
答案 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
如果您使用延迟,则更难忘记一个需要清理的地方。