如何在Node.js web应用程序中管理MongoDB连接?

如何在Node.js web应用程序中管理MongoDB连接?,node.js,mongodb,database-connection,connection-pooling,Node.js,Mongodb,Database Connection,Connection Pooling,我正在使用MongoDB的驱动程序来编写一个网站 我有一些关于如何管理连接的问题: 对于所有请求,仅使用一个MongoDB连接就足够了吗?是否存在任何性能问题?如果没有,我可以设置全局连接以在整个应用程序中使用吗 如果不是,那么在请求到达时打开一个新连接,并在处理请求时关闭它是否好?打开和关闭连接是否昂贵 我应该使用全局连接池吗?我听说驱动程序有一个本机连接池。这是一个好的选择吗 如果我使用连接池,应该使用多少个连接 还有其他我应该注意的事情吗 我一直在我的应用程序中使用带有redis连接的通用

我正在使用MongoDB的驱动程序来编写一个网站

我有一些关于如何管理连接的问题:

  • 对于所有请求,仅使用一个MongoDB连接就足够了吗?是否存在任何性能问题?如果没有,我可以设置全局连接以在整个应用程序中使用吗

  • 如果不是,那么在请求到达时打开一个新连接,并在处理请求时关闭它是否好?打开和关闭连接是否昂贵

  • 我应该使用全局连接池吗?我听说驱动程序有一个本机连接池。这是一个好的选择吗

  • 如果我使用连接池,应该使用多少个连接

  • 还有其他我应该注意的事情吗


  • 我一直在我的应用程序中使用带有redis连接的通用池-我强烈推荐它。它是通用的,我肯定知道它可以与mysql一起使用,所以我认为它和mongo不会有任何问题

    当应用启动并重新使用时,打开do MongoClient.connect一次 数据库对象。它不是一个单例连接池。连接 创建一个新的连接池


    因此,为了直接回答您的问题,重用由生成的db对象。这为您提供了池,并且与在每个db操作上打开/关闭连接相比,将提供显著的速度提高。

    如果您有Express.js,您可以使用它在没有池的请求之间缓存和共享MongoDB连接(因为公认的答案说这是共享连接的正确方式)


    如果没有-您可以查看其源代码并在另一个框架中使用。

    在Node.js应用程序启动时打开一个新连接,并重用现有的
    db
    连接对象:

    /server.js
    /api/users.js

    来源:下面是一些管理MongoDB连接的代码

    var MongoClient = require('mongodb').MongoClient;
    var url = require("../config.json")["MongoDBURL"]
    
    var option = {
      db:{
        numberOfRetries : 5
      },
      server: {
        auto_reconnect: true,
        poolSize : 40,
        socketOptions: {
            connectTimeoutMS: 500
        }
      },
      replSet: {},
      mongos: {}
    };
    
    function MongoPool(){}
    
    var p_db;
    
    function initPool(cb){
      MongoClient.connect(url, option, function(err, db) {
        if (err) throw err;
    
        p_db = db;
        if(cb && typeof(cb) == 'function')
            cb(p_db);
      });
      return MongoPool;
    }
    
    MongoPool.initPool = initPool;
    
    function getInstance(cb){
      if(!p_db){
        initPool(cb)
      }
      else{
        if(cb && typeof(cb) == 'function')
          cb(p_db);
      }
    }
    MongoPool.getInstance = getInstance;
    
    module.exports = MongoPool;
    
    启动服务器时,调用
    initPool

    require("mongo-pool").initPool();
    
    然后,在任何其他模块中,您可以执行以下操作:

    var MongoPool = require("mongo-pool");
    MongoPool.getInstance(function (db){
        // Query your MongoDB database.
    });
    

    这是基于。看看它。

    在一个独立的模块中管理mongo连接池。这种方法有两个好处。首先,它使您的代码模块化,易于测试。其次,您不必在请求对象中混用数据库连接,因为请求对象不是数据库连接对象的位置。(鉴于JavaScript的特性,我认为将任何东西混合到由库代码构造的对象中是非常危险的)。因此,您只需要考虑导出两种方法的模块。code>connect=()=>Promise和
    get=()=>dbConnectionObject

    使用这样的模块,您可以首先连接到数据库

    // runs in boot.js or what ever file your application starts with
    const db = require('./myAwesomeDbModule');
    db.connect()
        .then(() => console.log('database connected'))
        .then(() => bootMyApplication())
        .catch((e) => {
            console.error(e);
            // Always hard exit on a database connection error
            process.exit(1);
        });
    
    在飞行中,您的应用程序只需在需要DB连接时调用
    get()

    const db = require('./myAwesomeDbModule');
    db.get().find(...)... // I have excluded code here to keep the example  simple
    
    // myAwesomeDbModule.js
    let connection = null;
    
    module.exports.connect = () => new Promise((resolve, reject) => {
        MongoClient.connect(url, option, function(err, db) {
            if (err) { reject(err); return; };
            resolve(db);
            connection = db;
        });
    });
    
    module.exports.get = () => {
        if(!connection) {
            throw new Error('Call connect first!');
        }
    
        return connection;
    }
    
    如果您按照以下相同的方式设置db模块,那么您不仅可以确保应用程序不会启动,除非您有数据库连接,还可以使用全局方式访问数据库连接池,如果您没有连接,则会出错

    const db = require('./myAwesomeDbModule');
    db.get().find(...)... // I have excluded code here to keep the example  simple
    
    // myAwesomeDbModule.js
    let connection = null;
    
    module.exports.connect = () => new Promise((resolve, reject) => {
        MongoClient.connect(url, option, function(err, db) {
            if (err) { reject(err); return; };
            resolve(db);
            connection = db;
        });
    });
    
    module.exports.get = () => {
        if(!connection) {
            throw new Error('Call connect first!');
        }
    
        return connection;
    }
    

    我在我的项目中实现了以下代码,以在我的代码中实现连接池,这样它将在我的项目中创建一个最小的连接,并重用可用的连接

    /* Mongo.js*/
    
    var MongoClient = require('mongodb').MongoClient;
    var url = "mongodb://localhost:27017/yourdatabasename"; 
    var assert = require('assert');
    
    var connection=[];
    // Create the database connection
    establishConnection = function(callback){
    
                    MongoClient.connect(url, { poolSize: 10 },function(err, db) {
                        assert.equal(null, err);
    
                            connection = db
                            if(typeof callback === 'function' && callback())
                                callback(connection)
    
                        }
    
                    )
    
    
    
    }
    
    function getconnection(){
        return connection
    }
    
    module.exports = {
    
        establishConnection:establishConnection,
        getconnection:getconnection
    }
    
    /*app.js*/
    // establish one connection with all other routes will use.
    var db = require('./routes/mongo')
    
    db.establishConnection();
    
    //you can also call with callback if you wanna create any collection at starting
    /*
    db.establishConnection(function(conn){
      conn.createCollection("collectionName", function(err, res) {
        if (err) throw err;
        console.log("Collection created!");
      });
    };
    */
    
    // anyother route.js
    
    var db = require('./mongo')
    
    router.get('/', function(req, res, next) {
        var connection = db.getconnection()
        res.send("Hello");
    
    });
    

    您应该创建一个连接作为服务,然后在需要时重用它

    // db.service.js
    import { MongoClient } from "mongodb";
    import database from "../config/database";
    
    const dbService = {
      db: undefined,
      connect: callback => {
        MongoClient.connect(database.uri, function(err, data) {
          if (err) {
            MongoClient.close();
            callback(err);
          }
          dbService.db = data;
          console.log("Connected to database");
          callback(null);
        });
      }
    };
    
    export default dbService;
    
    我的App.js示例

    // App Start
    dbService.connect(err => {
      if (err) {
        console.log("Error: ", err);
        process.exit(1);
      }
    
      server.listen(config.port, () => {
        console.log(`Api runnning at ${config.port}`);
      });
    });
    
    无论你想在哪里使用它

    import dbService from "db.service.js"
    const db = dbService.db
    

    实现连接池的最佳方法是,您应该创建一个全局数组变量,该变量保存由
    MongoClient
    返回的连接对象的db name,然后在需要联系数据库时重用该连接

  • 在您的
    Server.js
    define
    var global.dbconnections=[]

  • 创建服务命名
    connectionService.js
    。它将有两种方法
    getConnection
    createConnection
    。 因此,当用户调用
    getConnection()
    时,它将在全局连接变量中找到详细信息,并返回连接详细信息(如果已经存在),否则它将调用
    createConnection()
    并返回连接详细信息

  • 使用
    调用此服务,它将返回connection对象,如果它已经有了其他对象,它将创建新连接并将其返回给您

  • 希望有帮助:)

    以下是
    connectionService.js
    代码:

    var mongo = require('mongoskin');
    var mongodb = require('mongodb');
    var Q = require('q');
    var service = {};
    service.getConnection = getConnection ;
    module.exports = service;
    
    function getConnection(appDB){
        var deferred = Q.defer();
        var connectionDetails=global.dbconnections.find(item=>item.appDB==appDB)
    
        if(connectionDetails){deferred.resolve(connectionDetails.connection);
        }else{createConnection(appDB).then(function(connectionDetails){
                deferred.resolve(connectionDetails);})
        }
        return deferred.promise;
    }
    
    function createConnection(appDB){
        var deferred = Q.defer();
        mongodb.MongoClient.connect(connectionServer + appDB, (err,database)=> 
        {
            if(err) deferred.reject(err.name + ': ' + err.message);
            global.dbconnections.push({appDB: appDB,  connection: database});
            deferred.resolve(database);
        })
         return deferred.promise;
    } 
    

    如果使用express,还有另一种更直接的方法,即利用express的内置功能在应用程序中的路由和模块之间共享数据。有一个名为app.locals的对象。我们可以将属性附加到它,并从路由内部访问它。要使用它,请在app.js文件中实例化mongo连接

    var-app=express();
    MongoClient.connect('mongodb://localhost:27017/')
    。然后(客户端=>{
    const db=client.db('your-db');
    const collection=db.collection('your-collection');
    app.locals.collection=集合;
    });
    //查看引擎设置
    app.set('views',path.join('views');
    
    现在,您可以使用
    req.app.locals
    在您的路由中访问此数据库连接,或者您希望在应用程序模块周围共享的任何其他数据,如下所示,而无需创建和需要其他模块

    app.get('/',(req,res)=>{
    const collection=req.app.locals.c