使用Go连接MongoDB时遇客户端断开错误及空指针Panic
问题分析与修复
核心问题
你的dbConnection函数里使用了defer client.Disconnect(...),这会导致函数返回*mongo.Collection时,MongoDB客户端已经被断开。因为defer语句会在函数执行完毕退出时立刻执行,而你返回的集合对象依赖于这个已断开的客户端,后续调用coll.Find()自然会报错client is disconnected;同时因为cursor为nil,调用cursor.All()会触发空指针panic。
修复方案
正确的做法是让MongoDB客户端的生命周期与应用程序生命周期保持一致,不要在获取集合的函数里立即断开客户端。可以将客户端初始化放在全局作用域,或者由上层调用方统一管理连接和断开逻辑。
修正后的代码示例
- 全局初始化客户端:
import ( "context" "fmt" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) // 全局客户端变量,复用单个实例 var client *mongo.Client func init() { serverAPI := options.ServerAPI(options.ServerAPIVersion1) opts := options.Client().ApplyURI("mongodb+srv://username:pwd@domain").SetServerAPIOptions(serverAPI) var err error client, err = mongo.Connect(context.TODO(), opts) if err != nil { panic(err) } // 可选:验证连接是否正常 if err := client.Ping(context.TODO(), nil); err != nil { panic(err) } } // 单独封装获取集合的函数 func getCollection(dbName, collName string) *mongo.Collection { return client.Database(dbName).Collection(collName) } // 程序退出时统一断开客户端 func cleanup() { if err := client.Disconnect(context.TODO()); err != nil { panic(err) } }
- 修改调用函数:
func sortByName() { coll := getCollection("testdb", "test") filter := bson.D{{Key: "name", Value: "joe"}} opts := options.Find().SetSort(bson.D{{Key: "name", Value: 1}}) cursor, err := coll.Find(context.TODO(), filter, opts) if err != nil { fmt.Printf("err in FIND: %v\n", err) return } defer cursor.Close(context.TODO()) // 使用完cursor后关闭,避免资源泄漏 var results []bson.D err = cursor.All(context.TODO(), &results) if err != nil { fmt.Printf("err in cursor: %v\n", err) return } for _, result := range results { fmt.Printf("result: %v\n", result) } }
- 在main函数中管理生命周期:
func main() { defer cleanup() // 程序退出时自动断开客户端 sortByName() }
额外注意事项
- MongoDB客户端本身是线程安全的,无需频繁创建和断开,复用单个实例即可。
- 必须在使用完cursor后调用
cursor.Close(),避免数据库连接资源泄漏。 - 添加客户端ping验证可以提前发现连接问题,避免后续操作报错。
内容的提问来源于stack exchange,提问作者Shakthi Thillai
相关产品推荐
相关产品推荐

