如何在 Go 中重用 MongoDB 连接 [英] How to reuse MongoDB connection in Go

查看:60
本文介绍了如何在 Go 中重用 MongoDB 连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将用 Go 编写的服务器与 MongoDB 连接,但我不确定如何以有效的方式进行连接.我发现有几个例子实现了它,如下所示.

libs/mongodb/client.go

包mongodb进口 (语境"日志"项目/密钥"go.mongodb.org/mongo-driver/mongo"go.mongodb.org/mongo-driver/mongo/options")func GetClient() *mongo.Database {客户端,错误:= mongo.Connect(上下文背景(),options.Client().ApplyURI(keys.GetKeys().MONGO_URI),)如果错误!= nil {日志.致命(错误)}返回 client.Database(keys.GetKeys().MONGO_DB_NAME)}

services/user/findOne.go

打包用户服务进口 (语境"日志"项目/库/mongodb"项目/模型"go.mongodb.org/mongo-driver/bson")func FindOne(filter bson.M) (models.User, error) {var 用户模型.User集合 := mongodb.GetClient().Collection("users")结果:= collection.FindOne(context.TODO(),过滤器)如果 result.Err() != nil {返回用户,result.Err()}如果错误:= result.Decode(&user);错误!= 零{log.Println("用户解码失败,错误:", err)返回用户,错误}返回用户,无}

GetClient 函数返回一个数据库实例,然后在整个应用程序中使用该实例.这似乎有效,但我想知道这是否真的是最佳实践,因为它似乎在每次请求新客户端时都创建一个新连接,如第二个代码片段所示,还是该假设不正确?我还考虑将 GetClient 转换为单例,它总是返回相同的数据库实例,但在这种情况下如何处理丢失的连接?谢谢

解决方案

我就是这样做的.在服务启动时执行一次,然后将 MongoDatastore 对象传递给编排器、服务层和存储库层.我正在为 mongo 使用github.com/mongodb/mongo-go-driver/mongo"驱动程序.我认为它在内部监视和回收空闲连接.因此,只要不丢失对 mongo.Client 对象的引用,我们就不必担心连接断开.

<预><代码>const CONNECTED = "成功连接到数据库:%v"类型 MongoDatastore 结构 {db *mongo.Database会话 *mongo.Client记录器 *logrus.Logger}func NewDatastore(config config.GeneralConfig, logger *logrus.Logger) *MongoDatastore {var mongoDataStore *MongoDatastore数据库,会话:= 连接(配置,记录器)如果 db != nil &&会话 != nil {//日志语句也在这里mongoDataStore = new(MongoDatastore)mongoDataStore.db = dbmongoDataStore.logger = 记录器mongoDataStore.Session = 会话返回 mongoDataStore}logger.Fatalf("连接数据库失败:%v", config.DatabaseName)返回零}func connect(generalConfig config.GeneralConfig, logger *logrus.Logger) (a *mongo.Database, b *mongo.Client) {var connectOnce sync.Oncevar db *mongo.Databasevar session *mongo.ClientconnectOnce.Do(func() {db, session = connectToMongo(generalConfig, logger)})返回数据库,会话}func connectToMongo(generalConfig config.GeneralConfig, logger *logrus.Logger) (a *mongo.Database, b *mongo.Client) {变量错误会话,错误:= mongo.NewClient(generalConfig.DatabaseHost)如果错误!= nil {logger.Fatal(错误)}session.Connect(context.TODO())如果错误!= nil {logger.Fatal(错误)}var DB = session.Database(generalConfig.DatabaseName)logger.Info(CONNECTED,generalConfig.DatabaseName)返回数据库,会话}

您现在可以按如下方式创建您的存储库:-

type TestRepository interface{Find(ctx context.Context, filters interface{}) []Document, error}类型 testRepository 结构 {存储 *datastore.MongoDatastore}func (r *testRepository) Find(ctx context.Context , filters interface{}) []Document, error{cur, err := r.store.GetCollection("some_collection_name").Find(ctx, filters)如果错误!= nil {返回零,错误}延迟 cur.Close(ctx)var 结果 = make([]models.Document, 0)对于 cur.Next(ctx) {var currDoc 模型.Document错误 := cur.Decode(&currDoc)如果错误!= nil {//登录这里继续}结果 = 追加(结果,currDoc)}返回结果,错误}

I would like to connect my server that was written in Go with a MongoDB but I'm not sure how to do it in an efficient way. A couple of examples I found implemented it like shown below.

libs/mongodb/client.go

package mongodb

import (
    "context"
    "log"
    "project/keys"

    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

func GetClient() *mongo.Database {
    client, err := mongo.Connect(
        context.Background(),
        options.Client().ApplyURI(keys.GetKeys().MONGO_URI),
    )

    if err != nil {
        log.Fatal(err)
    }

    return client.Database(keys.GetKeys().MONGO_DB_NAME)
}

services/user/findOne.go

package userservices

import (
    "context"
    "log"
    "project/libs/mongodb"
    "project/models"

    "go.mongodb.org/mongo-driver/bson"
)

func FindOne(filter bson.M) (models.User, error) {
    var user models.User

    collection := mongodb.GetClient().Collection("users")
    result := collection.FindOne(context.TODO(), filter)

    if result.Err() != nil {
        return user, result.Err()
    }

    if err := result.Decode(&user); err != nil {
        log.Println("Failed to decode user with error:", err)
        return user, err
    }

    return user, nil
}

The GetClient function returns a database instance that is then used throughout the app. This seems to work, but I'm wondering if this really is best practice as it seems to create a new connection every time a new client is requested as shown in the second code snippet or is that assumption incorrect? I also thought about converting GetClient to a singleton, that always returns the same database instance but how would a lost connection be handled in that case? Thank you

解决方案

I do it this way. Do it once at the service start and then pass the MongoDatastore object around to orchestrator, service layers and repository layers. I am using the "github.com/mongodb/mongo-go-driver/mongo" driver for mongo. I think it internally monitors and recycles idle connections. Hence, we don't have to bother about broken connections as long as reference to the mongo.Client object is not lost.


const CONNECTED = "Successfully connected to database: %v"

type MongoDatastore struct {
    db      *mongo.Database
    Session *mongo.Client
    logger  *logrus.Logger
}

func NewDatastore(config config.GeneralConfig, logger *logrus.Logger) *MongoDatastore {

    var mongoDataStore *MongoDatastore
    db, session := connect(config, logger)
    if db != nil && session != nil {

        // log statements here as well

        mongoDataStore = new(MongoDatastore)
        mongoDataStore.db = db
        mongoDataStore.logger = logger
        mongoDataStore.Session = session
        return mongoDataStore
    }

    logger.Fatalf("Failed to connect to database: %v", config.DatabaseName)

    return nil
}

func connect(generalConfig config.GeneralConfig, logger *logrus.Logger) (a *mongo.Database, b *mongo.Client) {
    var connectOnce sync.Once
    var db *mongo.Database
    var session *mongo.Client
    connectOnce.Do(func() {
        db, session = connectToMongo(generalConfig, logger)
    })

    return db, session
}

func connectToMongo(generalConfig config.GeneralConfig, logger *logrus.Logger) (a *mongo.Database, b *mongo.Client) {

    var err error
    session, err := mongo.NewClient(generalConfig.DatabaseHost)
    if err != nil {
        logger.Fatal(err)
    }
    session.Connect(context.TODO())
    if err != nil {
        logger.Fatal(err)
    }

    var DB = session.Database(generalConfig.DatabaseName)
    logger.Info(CONNECTED, generalConfig.DatabaseName)

    return DB, session
}

You may now create your repository as below:-

type TestRepository interface{
    Find(ctx context.Context, filters interface{}) []Document, error
}

type testRepository struct {
    store      *datastore.MongoDatastore
}

func (r *testRepository) Find(ctx context.Context , filters interface{}) []Document, error{
    cur, err := r.store.GetCollection("some_collection_name").Find(ctx, filters)
    if err != nil {
        return nil, err
    }
    defer cur.Close(ctx)
    var result = make([]models.Document, 0)
    for cur.Next(ctx) {
        var currDoc models.Document
        err := cur.Decode(&currDoc)
        if err != nil {
            //log here
            continue
        }
        result = append(result, currDoc)
    }
    return result, err
}

这篇关于如何在 Go 中重用 MongoDB 连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆