You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 05:12:34