我正在重写一个旧 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);
});
我会说,这是一个很好的猜测,实际上工作相对良好。除了这部分,它忽略了第一个项目之后的每个项目......这使得这非常没用。所以,我试了...
请求.multiple = true
...我想,它会完成这项工作。但是 - 令人惊讶的是 - 它没有,仍然只插入第一个项目。
使用 '?' 对于参数
此时我才真正开始寻找解决方案,因为第二个只是在模块文档中快速搜索。我偶然发现了这个答案并立即尝试了。没过多久,我的终端就吐出了一个
RequestError:“?”附近的语法不正确。
这么多。
批量插入
一些进一步的研究导致批量插入。非常有趣,很酷的功能以及OP解决方案对问题的出色更新!我从这里开始有些挣扎,但最终它看起来非常好:插入了多条记录,并且值似乎没问题。
直到我添加了子查询。将它用作声明的列的值不会导致任何错误,但是在检查表的值时,它只是显示一个
0作为该列的值。一点也不意外,但每个人都可以梦想,对吧?
懒惰的方式
我真的不知道该怎么想:
// simplified
Promise.all(aValues.map(oValue => {
return oPool.request().then(oRequest =>
oRequest
.input("col2", sql.Int, oValue.col2)
.input("col3", sql.Int, oValue.col3)
.input("col4", sql.Int, oValue.col4)
.query(sQuery);
});
});
它完成了这项工作,但如果任何请求由于某种原因失败,其他非失败插入仍将被执行,即使这不应该是可能的。
懒惰+交易
即使某些失败仍然是最后一种方法的主要问题,我尝试围绕它建立一个事务。所有查询都成功?好,承诺。任何查询都有错误?好吧,只是回滚比。所以我建立了一个事务,将我的 Promise.all 构造移到其中并再次尝试。Aaand 在我的终端中弹出下一个错误:
TransactionError: Can't acquire connection for the request. There is another request in progress.
如果你走到这一步,我不需要告诉你问题是什么。
概括
我还没有尝试(我不认为我会尝试这个)是使用事务方式并按顺序调用语句。我不相信这是要走的路。
而且我也不认为应该使用惰性方式,因为它对要插入的每条记录使用单个请求,而这可以通过某种方式仅使用一个请求来完成。只是这不知怎的,我不知道,现在不在我的脑海里。所以,如果你有什么可以帮助我的,请告诉我。
另外,如果您发现我的代码有任何其他问题,请随时指出。我不认为自己是初学者,但我也不认为学习会永远结束。:)