2017-09-28 22 views
0

当我读取golang SQL /数据库示例中“事务”中“Prepared”语句的示例时。其中一行表示“危险”,但代码示例没有提供替代方法。golang sql/database在事务中准备的语句

我想有下面的查询更加明确的解释,因为没有太多的信息,在提供Wiki页面上 - 如果你在defer stmt.Close()它提到看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”将在末尾运行代码,但这些代码是否意味着上述代码有误,应该用下面的代码或其他更好的替代代码替换。

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

可能是那个Close返回一个被忽略的错误。你的版本有同样的问题。你可以将close放在一个func中,以便更安全地使用延迟,或者在第二个版本中返回错误并检查tx的完整性。 – saarrrr

+1

评论说延期在Go 1.4中很危险,但是很久以前就修复了这个问题。使用log.Fatal也是不幸的。我不确定我是否会用这个例子,你可以看看sql pkg的例子,虽然这些例子不包括准备好的语句https://golang.org/pkg/database/sql/#pkg-例子 –

+0

是的,我不会使用'致命'。我会做一些像https://stackoverflow.com/a/46476451/2819754 –

回答

1

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 

如果您使用的延迟,这是很难忘记一个地方,你需要清理的东西了。