2017-09-28 44 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 

如果您使用的延遲,這是很難忘記一個地方,你需要清理的東西了。