我在MongoDB中使用node-mongodb-native驱动程序来编写网站。
我对如何管理连接有一些疑问:
仅使用一个MongoDB连接就可以处理所有请求是否足够?是否存在性能问题?如果没有,是否可以设置全局连接以在整个应用程序中使用?
如果不是,在请求到达时打开一个新的连接,并在处理请求时关闭它,这会很好吗?打开和关闭连接是否昂贵?
我应该使用全局连接池吗?我听说驱动程序具有本地连接池。这是一个好选择吗?
如果使用连接池,应该使用多少个连接?
还有其他我应该注意的事情吗?
我在MongoDB中使用node-mongodb-native驱动程序来编写网站。
我对如何管理连接有一些疑问:
仅使用一个MongoDB连接就可以处理所有请求是否足够?是否存在性能问题?如果没有,是否可以设置全局连接以在整个应用程序中使用?
如果不是,在请求到达时打开一个新的连接,并在处理请求时关闭它,这会很好吗?打开和关闭连接是否昂贵?
我应该使用全局连接池吗?我听说驱动程序具有本地连接池。这是一个好选择吗?
如果使用连接池,应该使用多少个连接?
还有其他我应该注意的事情吗?
Answers:
您的应用程序启动并重新使用db对象时,只需打开一次do MongoClient.connect。每个.connect都不是一个单例连接池。
因此,要直接回答您的问题,请重复使用产生的db对象MongoClient.connect()
。与每个数据库操作上的打开/关闭连接相比,这可以为您提供缓冲,并且速度会明显提高。
req.db
使用以下中间件将数据库对象保存到其中:github.com/floatdrop/express-mongo-db
Node.js应用程序启动时打开一个新连接,并重用现有的db
连接对象:
/server.js
import express from 'express';
import Promise from 'bluebird';
import logger from 'winston';
import { MongoClient } from 'mongodb';
import config from './config';
import usersRestApi from './api/users';
const app = express();
app.use('/api/users', usersRestApi);
app.get('/', (req, res) => {
res.send('Hello World');
});
// Create a MongoDB connection pool and start the application
// after the database connection is ready
MongoClient.connect(config.database.url, { promiseLibrary: Promise }, (err, db) => {
if (err) {
logger.warn(`Failed to connect to the database. ${err.stack}`);
}
app.locals.db = db;
app.listen(config.port, () => {
logger.info(`Node.js app is listening at http://localhost:${config.port}`);
});
});
/api/users.js
import { Router } from 'express';
import { ObjectID } from 'mongodb';
const router = new Router();
router.get('/:id', async (req, res, next) => {
try {
const db = req.app.locals.db;
const id = new ObjectID(req.params.id);
const user = await db.collection('user').findOne({ _id: id }, {
email: 1,
firstName: 1,
lastName: 1
});
if (user) {
user.id = req.params.id;
res.send(user);
} else {
res.sendStatus(404);
}
} catch (err) {
next(err);
}
});
export default router;
这是一些代码,将管理您的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.
});
这基于MongoDB文档。看一看。
在一个独立的模块中管理mongo连接池。这种方法有两个好处。首先,它使您的代码保持模块化并易于测试。其次,您不被迫在请求对象中混合数据库连接,而这不是数据库连接对象的位置。(鉴于JavaScript的性质,我认为将任何东西混入由库代码构造的对象都是非常危险的)。因此,您只需要考虑一个导出两个方法的模块。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);
});
在运行中,您的应用程序可以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;
}
get()
我们得到的是连接池而不是单个连接。顾名思义,连接池是数据库连接的逻辑集合。如果池中没有连接,驱动程序将尝试打开一个。打开该连接后,它将被使用并返回到池中。下次访问该池时,可以重新使用此连接。这里的好处是,池将为我们管理我们的连接,因此如果连接断开,我们可能永远不会知道,因为池将为我们打开一个新的连接。
如果您有Express.js,则可以使用express-mongo-db在没有池的情况下在请求之间缓存和共享MongoDB连接(因为已接受的答案说这是共享连接的正确方法)。
如果不是,您可以查看其源代码并在另一个框架中使用它。
我一直在我的应用程序中使用带有Redis连接的通用池-我强烈推荐它。它是通用的,我当然知道它可以与mysql一起使用,所以我认为您和mongo不会遇到任何问题
您应该将连接创建为服务,然后在需要时重用它。
// 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
http://mongoosejs.com/docs/api.html
查看猫鼬的来源。他们打开一个连接并将其绑定到Model对象,因此当需要Model Object时,将与数据库建立连接。驱动程序负责连接池。
mongodb
连接器。
我已经在我的项目中实现了以下代码,以在我的代码中实现连接池,因此它将在我的项目中创建一个最小的连接并重用可用的连接
/* 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");
});
实施连接池的最佳方法是,您应该创建一个全局数组变量,该变量具有MongoClient返回的连接对象的数据库名称,然后在需要联系数据库时重用该连接。
在您的Server.js中,定义var global.dbconnections = [];
创建一个服务命名connectionService.js。它将具有2个方法getConnection和createConnection。因此,当用户调用getConnection()时,它将在全局连接变量中查找详细信息并返回连接详细信息(如果已存在),否则它将调用createConnection()并返回连接详细信息。
使用db_name调用此服务,它将返回连接对象(如果已有的话),它将创建新的连接并将其返回给您。
希望能帮助到你 :)
这是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;
}
mongodb.com- >新项目->新集群->新集合->连接-> IP地址:0.0.0.0/0和数据库信用->连接应用程序->复制连接字符串并粘贴到节点的.env文件中应用程序,并确保用用户的实际密码替换“”,并用您的数据库名称替换“ / test”
创建新文件.env
CONNECTIONSTRING=x --> const client = new MongoClient(CONNECTIONSTRING)
PORT=8080
JWTSECRET=mysuper456secret123phrase
如果使用Express,则还有另一种更直接的方法,即利用Express的内置功能在应用程序内的路由和模块之间共享数据。有一个名为app.locals的对象。我们可以将属性附加到它并从我们的路线内部访问它。要使用它,请在app.js文件中实例化mongo连接。
var app = express();
MongoClient.connect('mongodb://localhost:27017/')
.then(client =>{
const db = client.db('your-db');
const collection = db.collection('your-collection');
app.locals.collection = collection;
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
现在,您可以通过以下方式在路由中访问此数据库连接或实际上希望共享的所有其他数据req.app.locals
,而无需创建和需要其他模块。
app.get('/', (req, res) => {
const collection = req.app.locals.collection;
collection.find({}).toArray()
.then(response => res.status(200).json(response))
.catch(error => console.error(error));
});
此方法可确保在应用程序运行期间一直打开数据库连接,除非您选择随时关闭它。它很容易访问,req.app.locals.your-collection
并且不需要创建任何其他模块。