如何在Go語言中多個goroutine共享數據庫連接并確保正確關閉?

如何在Go語言中多個goroutine共享數據庫連接并確保正確關閉?

go語言多goroutine共享數據庫連接及優雅關閉的最佳實踐

在Go語言中,多個goroutine共享數據庫連接并確保正確關閉是并發編程中的常見挑戰。本文將分析一個新手常見的錯誤示例,并提供最佳解決方案。

新手通常會嘗試使用defer db.Close()來關閉數據庫連接,但這種方法在多goroutine場景下無效。defer語句僅在當前goroutine結束時執行,無法保證所有goroutine結束后再關閉連接。將defer db.Close()放在共享數據庫連接的函數內部同樣無效,因為這會導致多個goroutine嘗試同時關閉同一個連接,引發錯誤。

一些新手嘗試使用sync.WaitGroup來協調goroutine的執行,并在所有goroutine完成后關閉連接。雖然可行,但代碼較為復雜。

更優雅的解決方案:使用連接池

立即學習go語言免費學習筆記(深入)”;

為了解決這個問題,并提高數據庫連接的利用率,建議使用連接池。連接池預先創建一定數量的數據庫連接,goroutine從池中獲取連接使用,用完后歸還到池中。當程序退出時,關閉連接池即可釋放所有連接。

以下是一個使用連接池的示例:

package main  import (     "database/sql"     "fmt"     "sync"      _ "github.com/go-sql-driver/mysql" // 替換成你的數據庫驅動 )  type dbConn struct {     conn *sql.DB     mu   sync.Mutex }  func (dc *dbConn) GetConn() (*sql.DB, error) {     dc.mu.Lock()     defer dc.mu.Unlock()     return dc.conn, nil }  func (dc *dbConn) Close() error {     dc.mu.Lock()     defer dc.mu.Unlock()     return dc.conn.Close() }  func querydb(dc *dbConn, i int) {     conn, err := dc.GetConn()     if err != nil {         fmt.Printf("Error getting connection: %vn", err)         return     }     defer conn.Close() // 這里關閉的是從池中獲取的連接,而不是池本身     // ... 數據庫操作 ... }  func main() {     db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database")     if err != nil {         panic(err)     }     defer db.Close() // 這里關閉的是連接池       dbConn := &dbConn{conn: db}     var wg sync.WaitGroup     for i := 0; i < 10; i++ {         wg.Add(1)         go func(i int) {             defer wg.Done()             querydb(dbConn, i)         }(i)     }     wg.Wait() } 

這個示例中,dbConn 結構體管理數據庫連接,GetConn 方法從連接池獲取連接,Close 方法關閉連接池。 querydb 函數從連接池獲取連接,使用后歸還。主函數負責創建和關閉連接池。sync.WaitGroup 用于等待所有goroutine完成。 請記得替換成你的數據庫驅動和連接字符串

使用連接池是處理Go語言多goroutine共享數據庫連接并確保正確關閉的最佳實踐,它不僅保證了連接的正確關閉,也提高了連接的復用率,避免了頻繁創建和銷毀連接的開銷。

? 版權聲明
THE END
喜歡就支持一下吧
點贊9 分享