Golang中Mgo会话每次都会创建新连接的问题

Golang中Mgo会话每次都会创建新连接的问题

func main() {
    session, err := mgo.Dial("mongodb://localhost")
    if err != nil {
        panic(err)
    }
    defer session.Close()
    
    db := session.DB("mydatabase")
    result := bson.M{}
    err = db.Run("serverStatus", &result)
    if err != nil {
        panic(err)
    }
    fmt.Println(result)
}

每当我执行 session.copy().DB(dbname) 时,db.serverStatus 的连接数都在增加,我需要避免这种情况。


更多关于Golang中Mgo会话每次都会创建新连接的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中Mgo会话每次都会创建新连接的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Mgo中,每次调用session.Copy()确实会创建一个新的连接池,这可能导致数据库连接数不断增加。为了避免这种情况,您应该重用现有的会话或使用连接池机制。

以下是几种解决方案:

1. 使用全局会话并复用

var globalSession *mgo.Session

func init() {
    session, err := mgo.Dial("mongodb://localhost")
    if err != nil {
        panic(err)
    }
    globalSession = session
}

func getDBSession() *mgo.Session {
    return globalSession.Copy()
}

func main() {
    session := getDBSession()
    defer session.Close()
    
    db := session.DB("mydatabase")
    result := bson.M{}
    err := db.Run("serverStatus", &result)
    if err != nil {
        panic(err)
    }
    fmt.Println(result)
}

2. 使用连接池配置

func main() {
    session, err := mgo.Dial("mongodb://localhost")
    if err != nil {
        panic(err)
    }
    defer session.Close()
    
    // 配置连接池
    session.SetPoolLimit(100) // 设置最大连接数
    session.SetMode(mgo.Monotonic, true)
    
    // 复用会话
    for i := 0; i < 10; i++ {
        go func(i int) {
            localSession := session.Copy()
            defer localSession.Close()
            
            db := localSession.DB("mydatabase")
            result := bson.M{}
            err := db.Run("serverStatus", &result)
            if err != nil {
                fmt.Printf("Error in goroutine %d: %v\n", i, err)
                return
            }
            fmt.Printf("Goroutine %d completed\n", i)
        }(i)
    }
    
    time.Sleep(2 * time.Second)
}

3. 使用单例模式管理会话

type MongoDBManager struct {
    session *mgo.Session
}

var instance *MongoDBManager
var once sync.Once

func GetMongoDBManager() *MongoDBManager {
    once.Do(func() {
        session, err := mgo.Dial("mongodb://localhost")
        if err != nil {
            panic(err)
        }
        session.SetPoolLimit(50)
        instance = &MongoDBManager{session: session}
    })
    return instance
}

func (m *MongoDBManager) GetSession() *mgo.Session {
    return m.session.Copy()
}

func main() {
    manager := GetMongoDBManager()
    session := manager.GetSession()
    defer session.Close()
    
    db := session.DB("mydatabase")
    result := bson.M{}
    err := db.Run("serverStatus", &result)
    if err != nil {
        panic(err)
    }
    fmt.Println(result)
}

4. 直接使用原始会话(适用于简单场景)

func main() {
    session, err := mgo.Dial("mongodb://localhost")
    if err != nil {
        panic(err)
    }
    defer session.Close()
    
    // 直接使用原始会话,不调用Copy()
    db := session.DB("mydatabase")
    result := bson.M{}
    err = db.Run("serverStatus", &result)
    if err != nil {
        panic(err)
    }
    fmt.Println(result)
}

关键点:

  • session.Copy()会创建新的连接池,应该谨慎使用
  • 在并发环境中,使用连接池限制最大连接数
  • 对于大多数用例,直接使用原始会话或复用少量会话副本即可
  • 记得在每个goroutine结束时调用session.Close()来释放连接
回到顶部