繁体   English   中英

使用 Node.js 向 SQL 服务器插入多个条目

[英]Insert multiple entries to SQL Server with Node.js

我正在重写一个旧的 API,为此我尝试使用节点模块mssql一次将多个值插入到 MSSQL-Server (2008) 数据库中。 现在,我有能力以某种方式做到这一点,但我希望遵循以下最佳实践 我已经完成了研究并尝试了很多事情来实现我的目标。 但是,我无法找到一个恰到好处的解决方案。

你可能想知道:

那么,您正在重写这个 API,那么一定有一种方法以前已经完成并且有效吗?

当然,你是对的,它以前是有效的,但是......不是我在重写中使用时感到舒服的方式。 让我向您展示它之前是如何完成的(当然添加了一点抽象):

const request = new sql.Request(connection);
let query = "INSERT INTO tbl (col1, col2, col3, col4) VALUES ";
for (/*basic for loop w/ counter variable i*/) {
    query += "(1, @col2" + [i] + ", @col3" + [i] + ", (SELECT x FROM y WHERE z = @someParam" + [i] + "))";
    // a check whether to add a comma or not
    request.input("col2" + [i], sql.Int(), values[i]);
    // ...
}
request.query(query, function(err, recordset) {
    // ...
}

虽然这很有效,但我不太认为这可以称为“最佳实践”之类的东西。 这也显示了最大的问题:子选择用于插入值。

到目前为止我尝试了什么

简单的方法

起初我尝试了最简单的方法:

// simplified
const sQuery = "INSERT INTO tbl (col1, col2, col3, col4) VALUES (1, @col2, @col3, (SELECT x FROM y WHERE z = @col4));";
oPool.request().then(oRequest => {
    return oRequest
        .input("col2", sql.Int(), aValues.map(oValue => oValue.col2))
        .input("col3", sql.Int(), aValues.map(oValue => oValue.col3))
        .input("col4", sql.Int(), aValues.map(oValue => oValue.col4))
        .query(sQuery);
});

我会说,这是一个很好的猜测,实际上工作得很好。 除了那部分,它忽略了第一个之后的每个项目......这使得它变得毫无用处。 所以,我尝试...

Request.multiple = true

......我想,它会完成这项工作。 但是 - 令人惊讶 - 它没有,仍然只插入了第一个项目。

使用 '?' 对于参数

在这一点上,我真正开始寻找解决方案,因为第二个只是在模块文档中快速搜索。 我偶然发现了这个答案并立即尝试了。 没多久我的终端就吐出一个

RequestError:'?' 附近的语法不正确。

这么多。

批量插入

一些进一步的研究导致了批量插入 非常有趣,很酷的功能和 OP 对问题的解决方案的出色更新,我在这里开始时遇到了一些困难:但最终它看起来非常好。 插入了多条记录,值似乎没问题。

直到我添加了子查询。 将它用作声明的列的值不会导致任何错误,但是在检查表的值时,它只是显示一个

0
作为此列的值。 一点也不奇怪,但每个人都可以做梦,对吧?

懒惰的方式

我真的不知道该怎么想:

TransactionError: Can't acquire connection for the request. There is another request in progress.

它完成了这项工作,但如果任何请求由于任何原因失败,其他未失败的插入仍将被执行,即使这是不可能的。

惰性+交易

由于即使有些失败也要继续是最后一种方法的主要问题,我尝试围绕它构建一个事务。 所有查询都成功了吗? 好,承诺。 任何查询都有错误? 好吧,只是回滚比。 所以我构建了一个事务,将我的 Promise.all 构造移入其中并再次尝试。 Aaand 下一个错误在我的终端中弹出:

 TransactionError: Can't acquire connection for the request. There is another request in progress.

如果你走到这一步,我不需要告诉你问题是什么。

概括

我还没有尝试过(而且我认为我不会尝试这个)的是使用事务方式并顺序调用语句。 我不相信这是通往 go 的路。

而且我也不认为应该使用懒惰的方式,因为它对要插入的每条记录使用单个请求,而这可以通过某种方式仅使用一个请求来完成。 只是不知何故,我不知道,现在不在我的脑海里。 所以,如果你有什么可以帮助我的,请告诉我。

另外,如果您发现我的代码有任何其他问题,请随时指出。 我不认为自己是初学者,但我也不认为学习会永远结束。 :)

我解决这个问题的方法是使用并发性为 1 的 PQueue 库。由于并发性为 1,它的速度很慢,但它适用于数千个查询:

    const transaction = sql.transaction();
    const request = transaction.request();
    const queue = new PQueue({ concurrency: 1 });

    // being transaction
    await transaction.begin();

    for (const query of queries) {
      queue.add(async () => {
        try {
          await request.query(query);
        } catch (err) {
          // stop pending transactions
          await queue.clear();
          await queue.onIdle();
          // rollback transaction
          await transaction.rollback();
          // throw error
          throw err;
        }
      });
    }
    // await queue
    await queue.onIdle();
    // comit transaction
    await transaction.commit();

暂无
暂无

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

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