如何在多个goroutine中正确关闭共享的数据库连接?

如何在多个goroutine中正确关闭共享的数据库连接?

go语言多goroutine共享数据库连接的优雅关闭

在Go语言并发编程中,多个goroutine共享数据库连接是常见场景。不当的连接关闭处理可能导致资源泄漏或其他问题。本文将分析问题并提供解决方案。

问题分析:

直接在主goroutine中使用defer db.Close()无法保证所有goroutine执行完毕后再关闭连接,因为主goroutine可能在子goroutine执行前就已结束。将db.Close()放在每个querydb函数中也不可行,因为这会导致多个goroutine竞争关闭同一个连接,引发错误。

解决方案:

使用WaitGroup同步goroutine的执行,确保所有goroutine完成任务后再关闭连接。

改进后的代码示例:

package main  import (     "fmt"     "sync"     "time" )  // 模拟数据库连接 type dbConn struct{}  func (c *dbConn) Close() error {     fmt.Println("Closing database connection...")     return nil }  func openDb() *dbConn {     fmt.Println("Opening database connection...")     return &dbConn{} }  func querydb(db *dbConn, i int, wg *sync.WaitGroup) {     defer wg.Done()     fmt.Printf("Goroutine %d querying database...n", i)     time.Sleep(time.Second) // 模拟查询操作 }  func main() {     db := openDb()     var wg sync.WaitGroup     for i := 0; i < 5; i++ {         wg.Add(1)         go querydb(db, i, &wg)     }     wg.Wait() // 等待所有goroutine完成     err := db.Close()     if err != nil {         fmt.Printf("Error closing database connection: %vn", err)     } } 

代码解释:

  1. 引入sync.WaitGroup用于同步goroutine。
  2. wg.Add(1)在启动每个goroutine前增加计数器。
  3. defer wg.Done()在每个goroutine结束后减少计数器。
  4. wg.Wait()阻塞主goroutine,直到所有计数器归零,即所有goroutine执行完毕。
  5. 最后,安全地关闭数据库连接。

此方法有效地解决了共享数据库连接的关闭问题,保证了资源的正确释放,避免了资源泄漏和并发错误。 其他方法,例如使用context包,也可以实现类似功能,但WaitGroup在此场景下更为简洁直接。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享