2017-04-23 26 views
2

我正在使用去插入一個新的用戶到MySQL數據庫。在插入用戶之前,我在msg表中保存某種「日誌消息」。兩個表(msguser)都有auto-increment。爲了接收通過自動增量選擇的id,我使用mysql的LAST_INSERT_ID()函數。這應該是線程安全的,正如許多關於堆棧溢出的其他討論中指出的,因爲它綁定到單個連接。Statement.Close影響mysql中線程安全的LAST_INSERT_ID在golang中嗎?

我問自己是否stmt.Close()stmt.Exec()會以任何方式改變mysql的行爲(特別是線程安全性)?

stmt, _ := db.Prepare("INSERT INTO msg (message) VALUES(?)") 
stmt.Exec(msg) 
stmt.Close() 

stmt, _ = db.Prepare("SELECT LAST_INSERT_ID()") 
stmt.QueryRow().Scan(&msgid) 
stmt.Close() 

stmt, _ = db.Prepare("INSERT INTO user (msg_id) VALUES(?)") 
stmt.Exec(msgid) 
stmt.Close() 

stmt, _ = db.Prepare("SELECT LAST_INSERT_ID()") 
stmt.QueryRow().Scan(&id) 
stmt.Close() 

回答

1

正如您所做的那樣關閉語句不會關閉數據庫連接。數據庫連接對於LAST_INSERT_ID很重要。除非您致電db.Close(),否則會關閉底層連接,您的連接將保持打開狀態。

然而,db池中的連接,所以不能保證你會得到後續查詢相同的連接,無論關閉連接的,除非你使用事務。

因此,在總結,你應該這樣做(添加錯誤處理,當然)

tx, _ := db.Begin() 

stmt, _ := tx.Prepare("INSERT INTO msg (message) VALUES(?)") 
stmt.Exec(msg) 
stmt.Close() 

stmt, _ = tx.Prepare("SELECT LAST_INSERT_ID()") 
stmt.QueryRow().Scan(&msgid) 
stmt.Close() 

_ = tx.Commit() 

但是,請注意,一個更好的方式來做到這一點是Result.LastInsertId

stmt, _ := tx.Prepare("INSERT INTO msg (message) VALUES(?)") 
res, _ := stmt.Exec(msg) 
stmt.Close() 

msgid := res.LastInsertId() 
+0

謝謝!我知道第一部分,但不知道有'事務'之類的東西。謝謝! :) –