如何在Go語言中正確關(guān)閉多個(gè)Goroutine共享的數(shù)據(jù)庫連接?

如何在Go語言中正確關(guān)閉多個(gè)Goroutine共享的數(shù)據(jù)庫連接?

go語言多Goroutine共享數(shù)據(jù)庫連接的優(yōu)雅關(guān)閉

在Go語言并發(fā)編程中,多個(gè)Goroutine共享數(shù)據(jù)庫連接是常見場景。不當(dāng)?shù)倪B接關(guān)閉方式可能導(dǎo)致數(shù)據(jù)丟失或程序崩潰。本文探討如何安全地關(guān)閉多個(gè)Goroutine共享的數(shù)據(jù)庫連接。

問題分析:

直接在主Goroutine使用defer db.Close()無法保證所有子Goroutine都已完成數(shù)據(jù)庫操作,可能導(dǎo)致連接提前關(guān)閉,引發(fā)錯(cuò)誤。在每個(gè)子Goroutine中使用defer db.Close()則會(huì)導(dǎo)致連接被多次關(guān)閉,同樣引發(fā)錯(cuò)誤。

解決方案:

立即學(xué)習(xí)go語言免費(fèi)學(xué)習(xí)筆記(深入)”;

推薦使用計(jì)數(shù)器和sync.WaitGroup來協(xié)調(diào)Goroutine的執(zhí)行和數(shù)據(jù)庫連接的關(guān)閉。

示例代碼:

package main  import (     "fmt"     "sync"     "time"      "database/sql"     _ "github.com/go-sql-driver/mysql" // 替換成你的數(shù)據(jù)庫驅(qū)動(dòng) )  type dbConn struct {     conn *sql.DB     wg   *sync.WaitGroup }  func openDb() (*dbConn, error) {     db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database") // 替換成你的數(shù)據(jù)庫連接字符串     if err != nil {         return nil, err     }     return &dbConn{conn: db, wg: &sync.WaitGroup{}}, nil }  func (dc *dbConn) close() error {     dc.wg.Wait() // 等待所有 Goroutine 完成     return dc.conn.Close() }  func querydb(dc *dbConn, i int) {     defer dc.wg.Done()     dc.wg.Add(1) // 計(jì)數(shù)器加1     // ... 數(shù)據(jù)庫操作 ...     time.Sleep(time.Second) // 模擬數(shù)據(jù)庫操作耗時(shí)     fmt.Printf("Goroutine %d finishedn", i) }  func main() {     dc, err := openDb()     if err != nil {         fmt.Println("Error opening database:", err)         return     }     defer dc.close() // 確保最后關(guān)閉連接      for i := 0; i < 5; i++ {         go querydb(dc, i)     }      fmt.Println("Main goroutine waiting...")     //time.Sleep(3*time.Second) // 可選:等待Goroutine完成,如果數(shù)據(jù)庫操作時(shí)間不確定,則需要其他機(jī)制等待 }

代碼解釋:

  1. dbConn 結(jié)構(gòu)體包含數(shù)據(jù)庫連接和sync.WaitGroup,用于管理Goroutine的執(zhí)行。
  2. openDb 函數(shù)打開數(shù)據(jù)庫連接并返回 dbConn 實(shí)例。
  3. close 方法使用 dc.wg.Wait() 等待所有 Goroutine 完成后,再關(guān)閉數(shù)據(jù)庫連接。
  4. querydb 函數(shù)在執(zhí)行數(shù)據(jù)庫操作前使用 dc.wg.Add(1) 增加計(jì)數(shù)器,操作完成后使用 defer dc.wg.Done() 減少計(jì)數(shù)器。
  5. main 函數(shù)啟動(dòng)多個(gè) Goroutine 執(zhí)行 querydb 函數(shù),最后使用 defer dc.close() 關(guān)閉數(shù)據(jù)庫連接。

這種方法確保所有 Goroutine 完成數(shù)據(jù)庫操作后,再關(guān)閉數(shù)據(jù)庫連接,避免了數(shù)據(jù)丟失和錯(cuò)誤。 記住替換示例代碼中的數(shù)據(jù)庫連接字符串和驅(qū)動(dòng)。 如果數(shù)據(jù)庫操作時(shí)間不可預(yù)測,可能需要更復(fù)雜的機(jī)制來等待所有Goroutine完成,例如使用channel進(jìn)行信號通知。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊12 分享