在Go语言中,如何正确关闭多个Goroutine共享的数据库连接?

在Go语言中,如何正确关闭多个Goroutine共享的数据库连接?

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

在Go语言并发编程中,多个Goroutine共享数据库连接时,如何安全地关闭连接是一个关键问题。不当的关闭方式可能导致数据丢失或程序崩溃。本文将探讨几种方案,并分析其优缺点。

假设我们有一个场景:多个Goroutine并发执行数据库查询操作,共享同一个数据库连接。

错误示范:使用defer在主Goroutine关闭连接

以下代码演示了一个常见的错误:

立即学习go语言免费学习笔记(深入)”;

db := openDB() defer db.Close() // 错误:在主Goroutine关闭,其他Goroutine可能仍在使用  for i := 0; i < 10; i++ {     go func(i int) {         queryDB(db, i)     }(i) } // ... 其他代码 ...

defer db.Close() 会在主Goroutine结束时执行,但此时其他Goroutine可能仍在使用数据库连接,导致程序崩溃或数据错误。

错误示范:在每个Goroutine中关闭连接

将db.Close()放在每个Goroutine中也不是正确的方案:

func queryDB(db *DB, i int) {     defer db.Close() // 错误:每个Goroutine都尝试关闭连接     // ... 数据库查询操作 ... }

这会导致连接被多次关闭,引发错误。

正确方案一:使用WaitGroup同步Goroutine

使用sync.WaitGroup可以确保所有Goroutine都完成工作后再关闭连接:

var wg sync.WaitGroup db := openDB() defer db.Close() // 正确:在所有Goroutine完成后关闭  for i := 0; i < 10; i++ {     wg.Add(1)     go func(i int) {         defer wg.Done()         queryDB(db, i)     }(i) } wg.Wait() // 等待所有Goroutine完成

此方法通过wg.Add(1)和wg.Done()来计数Goroutine,wg.Wait()阻塞直到所有Goroutine完成,确保连接在安全的时间点关闭。

正确方案二:使用全局变量和主Goroutine控制

另一种更简洁的方法是将数据库连接定义为全局变量,并在主Goroutine中统一管理:

var db *DB  func main() {     db = openDB()     defer db.Close() // 正确:在主Goroutine统一关闭      // ... 启动Goroutine ... }  func queryDB(i int) {     // ... 数据库查询操作 ... }

这种方式清晰地将连接的管理集中在主Goroutine,避免了并发访问和关闭的问题。

选择哪种方案取决于具体应用场景和代码复杂度。WaitGroup方法适用于更复杂的并发场景,而全局变量方法在简单场景下更简洁易懂。 关键在于确保数据库连接只被关闭一次,并且在所有Goroutine完成操作之后关闭。

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