具有多个查询的nodejs mysql连接池

0h4hbjxa  于 2021-06-17  发布在  Mysql
关注(0)|答案(2)|浏览(675)

我对nodejs还比较陌生(有php背景)。我对nodejs的异步特性和php的阻塞特性有了基本的了解。我已经创建了一些连接到mysql的应用程序节点,并让它们正常工作。
我目前对在node中执行查询的最佳方式的理解是:
创建连接池
当需要执行查询时:
池中的getconnection()
执行查询
.release()连接
我所处的情况是,我需要迭代大量的项,并将每个项插入到数据库中。做上面的事不管用。我的想法是,由于每个查询都是并行执行的,所以列表中的下一项试图获取连接,但由于前面的查询可能尚未完成,因此没有可用的连接。没有抛出错误,只是好像没有放入项目。通过日志记录,我发现它永远不会运行pool.getconnection()回调。
所以我想我可以修改连接流程:
创建连接池
当您需要执行许多查询时:
池中的getconnection()
迭代需要查询的项
执行查询
.release()连接
问题是,我如何知道何时可以安全地释放我的连接?我不能只在我的.query()回调中这样做,因为后面可能会有更多的查询。但我也不能在查询回调中这样做,因为我知道我需要等待所有查询完成。我是否有责任创建自己的逻辑,以确定所有查询(以及所有可能的未来查询,即使它们尚未启动)何时完成?或者这只是一件没做的事?
在php中,这将是微不足道的,因为它是阻塞性的。我选择在这个应用程序中使用nodejs,因为它有时确实需要异步。但在我的应用程序不需要异步的地方(在某些情况下不应该使用异步)。
我很犹豫是否发布我的代码,因为它有点复杂,所以我不想从这个特定的主题转移注意力。

o2rvlv0m

o2rvlv0m1#

迭代项目并插入数据库是一个错误的选择!在循环中构建一个对象数组,然后使用bulkinsert一次性插入所有项。这样,只需调用一次getconnection(),然后在批量插入之后调用.release()。
如果不是这样,那么在交互过程中您需要调用
1) getconnection()2)执行查询3)call.release()
对所有项目重复步骤1至步骤3。
最后一次迭代时,您需要调用callback()函数将响应返回给调用函数。

zbsbpyhn

zbsbpyhn2#

你的连接流程很好。如果只执行一个查询,实际上不需要执行任何步骤,只需调用 .query() 直接在游泳池上(其余的在引擎盖下)。
您需要在一个事务中执行多个查询的情况通常是,但我将添加事务支持:
创建连接池
当您需要执行许多查询时:
池中的getconnection()
启动事务
迭代需要查询的项
执行查询
如果有任何失败,停止并回滚
如果全部成功,请提交
.release()连接
如果所有的查询都“完成”,您知道何时释放连接。你怎么知道已经完成了?不止一种方法。我建议您使用promise api,因此它可能如下所示:

async function doStuff(items) {

  try { 
    const connection = await pool.getConnection();
    await connection.beginTransaction();
    for(const item of items) {
      await connection.query('....');
    }
    await connection.commit();
  } catch (e) {
    await connection.rollback();
    throw e;
  } finally {
    await connection.release();
  }

}

这种模式有几个优点:
它将正确地报告错误
它将在成功和出错时释放连接。
它要么完全失败,要么完全成功。这里不准半途而废。
如果您不关心事务,可以简化:

async function doStuff(items) {

  try { 
    const connection = await pool.getConnection();
    for(const item of items) {
      await connection.query('....');
    }
  } finally {
    await connection.release();
  }

}

这样做的问题是,您可能会获得部分成功,这通常是不可取的,尤其是对于api。不过,如果对你来说足够好,那就足够了。
如果您对没有事务感到满意,理论上可以完全跳过 getConnection 步骤:

async function doStuff(items) {
  for(const item of items) {
    await pool.query('....');
  }
}

这意味着所有的查询都可能在不同的连接上执行。这可能会降低性能,但会使代码更简单。
如何实现承诺?
这有点争议。为此,您可能需要切换mysql包。有一个 mysql2 具有 mysql2/promise 导入非常优秀的代码(并与更流行的 mysql Package )。最好换成这个。
如果我不想换包怎么办?
好吧,这个回调版本要痛苦得多。在这种情况下,我建议仍然使用promisefy,但是将回调转换为promise模式,也许使用“promisify”。
如果你真的不想要任何承诺,你基本上必须把我的例子转换成基于回调的,这看起来会更痛苦。

相关问题