繁体   English   中英

Mongodb节点驱动程序-当我调用db.close()真的很重要吗?还是我很幸运?

[英]Mongodb Node Driver - does it really matter when I call db.close() or am I getting lucky?

我发现db.close()似乎直到所有读取或写入完成才关闭,无论何时调用它。 这实际上是我想要的,但是我想确保这是预期的行为,而不仅仅是我很幸运。 我有一些这样的代码:

...
{
  collection.insertMany(...).then(()=> { console.log("inserted") })
  collection.deleteMany(...).then(()=> { console.log("deleted") })
}).then(() =>
{
  console.log("will close");
  client.close();
}).catch((reason) => { console.log(reason) });

我得到像这样的输出:

will close
deleted
inserted

但没有错误,经过进一步测试,实际上已插入和删除了正确的记录。 在文档中,我们看到无论最终回调是什么,它们都将调用db.close(),但是那时我没有这样做。 这可靠吗? 我不确定如何重组我的代码,以更清楚地知道在insertMany和deleteMany之后都发出了关闭-也许我应该使用promise.all。

编辑因此,下面的两个答案对我来说如何确保在适当的时间关闭连接都有意义,出于性能方面的考虑,尼尔·伦恩(Neil Lunn)的建议使用bulkWrite似乎是理想的选择。 出于良好实践的考虑,我暂时可能会在我的应用程序中使用bulkWrite路线,但对于最初的问题我仍然有些困惑...

在我看来,以上代码无论在client.close()之前都会发出insertMany和deleteMany,因此我认为mongodb知道有待处理的操作,因此将适当关闭。 有人可以给我一个示例方案来说明如何过早调用client.close()吗? 如果假设这两个操作中的任何一个错误都可能导致client.close()提前调用,那么我建议添加

{
  collection.insertMany(...).then(()=> { console.log("inserted") })
  collection.deleteMany(...).then(()=> { console.log("deleted") })
}).then(() =>
{
  console.log("will close");
}).catch((reason) => { console.log(reason) })
  .then(() => { client.close() })

您需要等待查询完成。 您可以通过返回Promise.all([query1, query2]) ,当查询返回的两个诺言都得到满足时,它将解决。 此外,使用Promise的.finally()方法可确保即使出现错误也可以调用client.close() 使用当前代码,如果发生错误,将不会调用client.close()

...
{
  return Promise.all([
    collection.insertMany(...).then(()=> { console.log("inserted") }),
    collection.deleteMany(...).then(()=> { console.log("deleted") })
  ]);
}).then(() => {
  console.log("will close");
}).catch((reason) => {
  console.log(reason);
}).finally(() => {
  client.close();
});

老实说,在调用client.close()之前,您不仅会“幸运”地解决要解决的操作,而且两个语句并行运行还可能会出现“潜在”问题。

理想情况下,您应该改用bulkWrite()并使用bulkWrite()包含的两个动作发出“单个”请求。 “单个请求”也具有“单个响应”,因此等待多个承诺的解决没有问题:

collection.bulkWrite(
  [
    ...listOfInsertDocuments.map(document => ({ "insertOne": { document } })),
    { "deleteMany": { "filter": filterCondition } }
  ]
)
.then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());

bulkWrite()的默认操作是对操作进行“排序”,并以与在“操作”数组中显示的顺序相同的顺序依次执行。 Array.map()这里用于创建insertOne动作的insertMany()恰好是insertMany()方法在底层驱动程序实现中实际执行的操作。

实际上,所有此类驱动程序方法实际上都将底层的“批量API”方法称为现代的处理方式。 当连接到MongoDB 2.6之前的MongoDB实例时, bulkWrite()显式地从实际的“ Bulk API”中抽象出来,以便将请求降级为“旧版” API。

另一种方法是通过显式设置"ordered": false执行“并行”执行"ordered": false

collection.bulkWrite(
  [
  ...listOfInsertDocuments.map(document => ({ "insertOne": { document } })),
  { "deleteMany": { "filter": filterCondition } }
  ],
  { "ordered": false }
)
.then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());

这故意意味着,所有动作都不依赖于其他动作完成“第一”动作。 因此,如果确实是在“插入”您也在“删除”的某物,则不能保证会以任何特定顺序发生。

除了“并行性”之外, "ordered": false的一般目的是"ordered": false是允许“错误时”继续。 在这种情况下,实际上会尝试所有“批处理”操作,并且在异常响应中,您会得到详细信息,告诉您所提供的操作数组中哪个“索引位置”出现任何故障。

然后,通过以下Promise.all()调用以“模仿”方式完成该行为:

Promise.all([
  collection.insertMany(..., { "ordered": false }).then(()=> { console.log("inserted") }),
  collection.deleteMany(...).then(()=> { console.log("deleted") })
]).then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());

这当然是“并行”执行的,但是会触发“多个请求”,这会导致与服务器的来回通信产生更大的开销。 先前示例的目的是避免这种情况,因此是一个更好的选择。

对于“完整性”,您当然可以始终“承诺”承诺:

  collection.insertMany(...)
    .then(() => console.log("inserted")),
    .then(() => collection.deleteMany(...)
    .then(()=> console.log("deleted"))
    .then(() => console.log("will close"))
    .catch(e => console.error(e))
    .then(() => client.close());

这样,“一切”都是串行执行的,但是它们当然都会发出单独的请求。

因此,尽管有多种方法可以处理“等待” Promise解决方案,但通常最好进行“一个呼叫”,然后等待“批量”响应。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM