基於gin的golang web開發:使用資料庫事務

陳巨集博發表於2020-11-11

在前文介紹訪問資料庫時介紹了github.com/jmoiron/sqlx包,本文基於這個包使用資料庫事務。

defer

在使用資料庫事務之前,首先需要了解go語言的defer關鍵字。defer是go語言的延遲執行語句,defer後面的語句會被go進行延遲處理,在函式即將結束的時候,defer後面的語句將逆序執行。也就是說,先defer的語句最後執行。defer很像java或者C#中的finally語句。下面通過一個例子看一下defer。

package main

import "fmt"

func main() {
	fmt.Println("defer 開始")
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
	panic("測試 panic")
	fmt.Println("defer 結束")
}

程式碼執行結果:

defer 開始
3
2
1
panic: 測試 panic

goroutine 1 [running]:
main.main()
	/tests/gookokok/main.go:10 +0x1b8

Process finished with exit code 2

通過執行結果可以看到defer的逆序輸出。在之後又手動觸發了一個panic,影響了最後一行的輸出defer 結束,go在觸發panic時優先執行了defer,足以證明defer是非常安全的,所以defer也常常被用來互斥解鎖、關閉檔案或資料庫事務的處理。

事務

sqlx使用事務和database/sql相比擴充套件出了MustBegin()、MustExec()等方法,這樣就不需要在程式碼中手動處理很多錯誤。MustBegin會在出現錯誤的時候觸發panic而不是返回錯誤,這樣就可以在程式碼的更上一層統一處理錯誤。

tx, err := db.Begin()
err = tx.Exec(...)
err = tx.Commit()

tx := db.MustBegin()
tx.MustExec(...)
err = tx.Commit()

sqlx支援以上兩種開啟事務的方法。MustBegin返回sqlx.Tx,sqlx.Tx也提供了Select,Get之類的API,執行資料庫操作和使用sqlx.DB是一樣的。

以上程式碼執行tx.MustExec(...)如果報錯的話,程式碼將沒有機會執行到tx.Commit(),這樣資料庫連線會等到go進行垃圾回收的時候才能關閉,而且很高併發的話,可能會佔滿資料庫連線數,造成站點無法訪問的情況。

tx := db.MustBegin()
defer tx.Rollback()
tx.MustExec(...)
err = tx.Commit()

程式碼中加入defer tx.Rollback()就可以解決問題。通過前面的介紹已知defer是在方法即將結束時執行,哪怕是程式碼出現異常也不會影響資料庫連線。

文章出處:基於gin的golang web開發:使用資料庫事務

相關文章