Golang连接MongoDB成功但插入文档触发空指针恐慌问题排查
问题描述
连接MongoDB成功,但插入文档时触发空指针 panic:
http: panic serving 172.27.0.8:40176: runtime error: invalid memory address or nil pointer dereference
main.go 初始化数据库连接代码
func main(){ //Connect to mongo mongoClient,err:=connectToMongo() if err!=nil{ log.Panic(err) } client=mongoClient //Create a context that mongo needs in order to disconnect ctx,_:=context.WithTimeout(context.Background(), 15*time.Second) // ctx,cancel:=context.WithTimeout(context.Background(), 15*time.Second) //defer cancel() //close connection defer func () { if err =client.Disconnect(ctx); err!=nil{ panic(err) } }() muxRouter := mux.NewRouter().StrictSlash(true) //specify who's allowed to connect c:=cors.New(cors.Options{ AllowedOrigins: []string{"https://*", "http://*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"}, ExposedHeaders: []string{"Link"}, AllowCredentials: true, MaxAge: 300, }) router := AddRoutes(muxRouter) handler := c.Handler(router) log.Println("Service stratring at o port ",webPort) sterr := http.ListenAndServe(":9090", handler) //Uncomment this line when using docker if sterr != nil { log.Fatal("error starting http server :: ", err) return } log.Println("Service started at port ",webPort) } func connectToMongo()(*mongo.Client,error){ mongoUsername := os.Getenv("MONGOUSERNAME") mongoPassword := os.Getenv("MONGOPASSWORD") //create connection options clientOptions:=options.Client().ApplyURI(mongoURL) clientOptions.SetAuth(options.Credential{ Username: mongoUsername, Password: mongoPassword, }) //connect c,err:=mongo.Connect(context.TODO(),clientOptions) if err!=nil{ log.Println("Error connecting to mongo",err) return nil,err } log.Println("Connected to mongo") return c,nil }
models.go 插入数据代码
var client *mongo.Client func Insert(entry LogEntry)error{ log.Printf("Attempting to insert %s", entry) log.Printf("client s %s", client) //db:=client.Database("logs") //log.Printf("database is %s", db) collection:=client.Database("logs").Collection("logsCollection") log.Printf("collection is %s", collection) _,err :=collection.InsertOne(context.TODO(), LogEntry{ Name: entry.Name, Data: entry.Data, CreatedAt: time.Now(), UpdatedAt: time.Now(), }) if err!=nil{ log.Println("Error inserting new record into logs collection",err) return err } log.Println("insert successful") return nil }
请问哪里操作出错了?
问题原因及修复方案
核心问题
你在main.go和models.go里各自定义了全局变量var client *mongo.Client,这两个变量属于独立作用域(若两个文件分属不同包则完全无关)。main.go里的client被赋值为MongoDB连接实例,但models.go里的client始终是nil,调用client.Database()时必然触发空指针 panic。
修复方案
方案1:依赖注入(推荐)
修改Insert函数,让它接收*mongo.Client参数,避免依赖全局变量:
// models.go func Insert(entry LogEntry, client *mongo.Client) error { log.Printf("Attempting to insert %s", entry) collection := client.Database("logs").Collection("logsCollection") _, err := collection.InsertOne(context.TODO(), LogEntry{ Name: entry.Name, Data: entry.Data, CreatedAt: time.Now(), UpdatedAt: time.Now(), }) if err != nil { log.Println("Error inserting new record into logs collection", err) return err } log.Println("insert successful") return nil }
在路由处理函数等调用Insert的位置,传入main.go中初始化好的client实例。
方案2:共享全局变量(仅限同包场景)
如果main.go和models.go属于同一个包,删除models.go里的var client *mongo.Client声明,确保使用的是main.go中定义的全局变量。但这种方式耦合性高,不建议在大型项目中使用。
方案3:包内初始化客户端
在models包中添加初始化函数,接收并赋值客户端实例:
// models.go var client *mongo.Client func InitMongoClient(c *mongo.Client) { client = c }
然后在main.go连接成功后调用初始化:
func main() { mongoClient, err := connectToMongo() if err != nil { log.Panic(err) } models.InitMongoClient(mongoClient) // ... 后续启动服务代码 }
内容的提问来源于stack exchange,提问作者Black Eyed Beans
相关产品推荐
相关产品推荐

