Javascript 何时关闭 Nodejs 中的 MongoDB 数据库连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8373905/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When to close MongoDB database connection in Nodejs
提问by realguess
Working with Nodejs and MongoDB through Node MongoDB native driver. Need to retrieve some documents, and make modification, then save them right back. This is an example:
通过 Node MongoDB 本机驱动程序使用 Nodejs 和 MongoDB。需要检索一些文件,并进行修改,然后将它们保存回来。这是一个例子:
db.open(function (err, db) {
db.collection('foo', function (err, collection) {
var cursor = collection.find({});
cursor.each(function (err, doc) {
if (doc != null) {
doc.newkey = 'foo'; // Make some changes
db.save(doc); // Update the document
} else {
db.close(); // Closing the connection
}
});
});
});
With asynchronous nature, if the process of updating the document takes longer, then when cursor reaches the end of documents, database connection is closed. Not all updates are saved to the database.
由于异步性质,如果更新文档的过程需要更长的时间,那么当光标到达文档末尾时,数据库连接将关闭。并非所有更新都保存到数据库中。
If the db.close()
is omitted, all the documents are correctly updated, but the application hangs, never exits.
如果db.close()
省略,则所有文档都正确更新,但应用程序挂起,永不退出。
I saw a post suggesting using a counter to track number of updates, when fall back to zero, then close the db. But am I doing anything wrong here? What is the best way to handle this kind of situation? Does db.close()
have to be used to free up resource? Or does a new db connection needs to open?
我看到一个帖子建议使用计数器来跟踪更新次数,当回落到零时,然后关闭数据库。但我在这里做错了什么吗?处理这种情况的最佳方法是什么?是否db.close()
必须以释放资源?还是需要打开一个新的数据库连接?
采纳答案by mpobrien
Here's a potential solution based on the counting approach (I haven't tested it and there's no error trapping, but it should convey the idea).
这是一个基于计数方法的潜在解决方案(我没有测试过它并且没有错误捕获,但它应该传达这个想法)。
The basic strategy is: Acquire the count of how many records need to be updated, save each record asynchronously and a callback on success, which will decrement the count and close the DB if the count reaches 0 (when the last update finishes). By using {safe:true}
we can ensure that each update is successful.
基本策略是:获取需要更新多少条记录的计数,异步保存每条记录并在成功时回调,如果计数达到0(最后一次更新完成时),它将递减计数并关闭数据库。通过使用{safe:true}
我们可以确保每次更新都成功。
The mongo server will use one thread per connection, so it's good to either a) close unused connections, or b) pool/reuse them.
mongo 服务器将为每个连接使用一个线程,因此最好 a) 关闭未使用的连接,或 b) 池/重用它们。
db.open(function (err, db) {
db.collection('foo', function (err, collection) {
var cursor = collection.find({});
cursor.count(function(err,count)){
var savesPending = count;
if(count == 0){
db.close();
return;
}
var saveFinished = function(){
savesPending--;
if(savesPending == 0){
db.close();
}
}
cursor.each(function (err, doc) {
if (doc != null) {
doc.newkey = 'foo'; // Make some changes
db.save(doc, {safe:true}, saveFinished);
}
});
})
});
});
回答by pkopac
It's best to use a pooled connection and then call db.close() in cleanup function at the end of your application's life:
最好使用池连接,然后在应用程序生命周期结束时在清理函数中调用 db.close() :
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
See http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html
见http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html
A bit old thread, but anyway.
有点旧的线程,但无论如何。
回答by cl yu
I found that using counter may apply to simple scenario, but may be hard in complicated situations. Here is a solution that I come up by closing the database connection when database connection is idle:
我发现使用 counter 可能适用于简单的场景,但在复杂的情况下可能很难。这是我通过在数据库连接空闲时关闭数据库连接提出的解决方案:
var dbQueryCounter = 0;
var maxDbIdleTime = 5000; //maximum db idle time
var closeIdleDb = function(connection){
var previousCounter = 0;
var checker = setInterval(function(){
if (previousCounter == dbQueryCounter && dbQueryCounter != 0) {
connection.close();
clearInterval(closeIdleDb);
} else {
previousCounter = dbQueryCounter;
}
}, maxDbIdleTime);
};
MongoClient.connect("mongodb://127.0.0.1:27017/testdb", function(err, connection)(
if (err) throw err;
connection.collection("mycollection").find({'a':{'$gt':1}}).toArray(function(err, docs) {
dbQueryCounter ++;
});
//do any db query, and increase the dbQueryCounter
closeIdleDb(connection);
));
This can be a general solution for any database Connections. maxDbIdleTime can be set as the same value as db query timeout or longer.
这可以是任何数据库连接的通用解决方案。maxDbIdleTime 可以设置为与 db 查询超时相同的值或更长时间。
This is not very elegant, but I can't think of a better way to do this. I use NodeJs to run a script that queries MongoDb and Mysql, and the script hangs there forever if the database connections are not closed properly.
这不是很优雅,但我想不出更好的方法来做到这一点。我使用 NodeJs 运行一个查询 MongoDb 和 Mysql 的脚本,如果数据库连接没有正确关闭,该脚本将永远挂在那里。
回答by Glenn
Here's a solution I came up with. It avoids using toArray and it's pretty short and sweet:
这是我想出的解决方案。它避免使用 toArray 并且它非常简短和甜蜜:
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://localhost:27017/mydb", function(err, db) {
let myCollection = db.collection('myCollection');
let query = {}; // fill in your query here
let i = 0;
myCollection.count(query, (err, count) => {
myCollection.find(query).forEach((doc) => {
// do stuff here
if (++i == count) db.close();
});
});
});
回答by Andrew Kirk
Based on the suggestion from @mpobrien above, I've found the asyncmodule to be incredibly helpful in this regard. Here's an example pattern that I've come to adopt:
根据上面@mpobrien 的建议,我发现async模块在这方面非常有用。这是我采用的示例模式:
const assert = require('assert');
const async = require('async');
const MongoClient = require('mongodb').MongoClient;
var mongodb;
async.series(
[
// Establish Covalent Analytics MongoDB connection
(callback) => {
MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
assert.equal(err, null);
mongodb = db;
callback(null);
});
},
// Insert some documents
(callback) => {
mongodb.collection('sandbox').insertMany(
[{a : 1}, {a : 2}, {a : 3}],
(err) => {
assert.equal(err, null);
callback(null);
}
)
},
// Find some documents
(callback) => {
mongodb.collection('sandbox').find({}).toArray(function(err, docs) {
assert.equal(err, null);
console.dir(docs);
callback(null);
});
}
],
() => {
mongodb.close();
}
);
回答by Sebastián Ezquerro
Modern way of doing this without counters, libraries or any custom code:
无需计数器、库或任何自定义代码的现代方法:
let MongoClient = require('mongodb').MongoClient;
let url = 'mongodb://yourMongoDBUrl';
let database = 'dbName';
let collection = 'collectionName';
MongoClient.connect(url, { useNewUrlParser: true }, (mongoError, mongoClient) => {
if (mongoError) throw mongoError;
// query as an async stream
let stream = mongoClient.db(database).collection(collection)
.find({}) // your query goes here
.stream({
transform: (readElement) => {
// here you can transform each element before processing it
return readElement;
}
});
// process each element of stream (async)
stream.on('data', (streamElement) => {
// here you process the data
console.log('single element processed', streamElement);
});
// called only when stream has no pending elements to process
stream.once('end', () => {
mongoClient.close().then(r => console.log('db successfully closed'));
});
});
Tested it on version 3.2.7 of mongodb driver but according to link might be valid since version 2.0
在 mongodb 驱动程序的 3.2.7 版上对其进行了测试,但根据链接可能自2.0 版起有效
回答by JJ Stiff
I came up with a solution that involves a counter like this. It does not depend on a count() call nor does it wait for a time out. It will close the db after all the documents in each() are exhausted.
我想出了一个涉及这样的计数器的解决方案。它不依赖于 count() 调用,也不等待超时。在 each() 中的所有文档都用完后,它将关闭数据库。
var mydb = {}; // initialize the helper object.
mydb.cnt = {}; // init counter to permit multiple db objects.
mydb.open = function(db) // call open to inc the counter.
{
if( !mydb.cnt[db.tag] ) mydb.cnt[db.tag] = 1;
else mydb.cnt[db.tag]++;
};
mydb.close = function(db) // close the db when the cnt reaches 0.
{
mydb.cnt[db.tag]--;
if ( mydb.cnt[db.tag] <= 0 ) {
delete mydb.cnt[db.tag];
return db.close();
}
return null;
};
So that each time you are going to make a call like db.each() or db.save() you would use these methods to ensure the db is ready while working and closed when done.
因此,每次您要进行 db.each() 或 db.save() 之类的调用时,您都可以使用这些方法来确保数据库在工作时准备好并在完成时关闭。
Example from OP:
来自 OP 的示例:
foo = db.collection('foo');
mydb.open(db); // *** Add here to init the counter.**
foo.find({},function(err,cursor)
{
if( err ) throw err;
cursor.each(function (err, doc)
{
if( err ) throw err;
if (doc != null) {
doc.newkey = 'foo';
mydb.open(db); // *** Add here to prevent from closing prematurely **
foo.save(doc, function(err,count) {
if( err ) throw err;
mydb.close(db); // *** Add here to close when done. **
});
} else {
mydb.close(db); // *** Close like this instead. **
}
});
});
Now, this assumes that the second to last callback from each makes it through the mydb.open() before the last callback from each goes to mydb.close().... so, of course, let me know if this is an issue.
现在,这假设从每个回调到 mydb.close() 之前,倒数第二个回调通过 mydb.open() 完成,然后从每个回调转到 mydb.close().... 所以,当然,让我知道这是否是问题。
So: put a mydb.open(db) before a db call and put a mydb.close(db) at the return point of the callback or after the db call (depending on the call type).
所以:在 db 调用之前放置一个 mydb.open(db) 并在回调的返回点或 db 调用之后放置一个 mydb.close(db) (取决于调用类型)。
Seems to me that this kind of counter should be maintained within the db object but this is my current workaround. Maybe we could create a new object that takes a db in the constructor and wrap the mongodb functions to handle the close better.
在我看来,这种计数器应该在 db 对象中维护,但这是我目前的解决方法。也许我们可以创建一个新对象,它在构造函数中接受一个 db 并包装 mongodb 函数以更好地处理关闭。