我正在尝试运行一个脚本,从一个数据库中提取记录,然后将记录插入另一个数据库,但在插入步骤中,我不断遇到此错误 8 或 9 次重复。
我对 node-mssql 库不是很熟悉,如果能对这里发生的事情有任何见解,我将不胜感激!我附上了堆栈跟踪和脚本的副本。
const sql = require('mssql')
const humENV = require('../env').humENV
const rbENV = require('../env').rbENV
const logger = require('./logger')
const getReviewHumanatic = async () => {
try {
let pool = await sql.connect(humENV.SQL_CONFIG)
let req = await pool.request()
.query(`
WITH cte
AS (SELECT DISTINCT TOP 500 htaskid,
ht.frn_leuserid,
ht.frn_callid,
ht.frn_hcatid,
ht.frn_hcat_optionid,
frn_lskinid,
cq.duration_seconds,
add_path,
CASE
WHEN call_queueid IS NULL THEN 3
ELSE 1
END AS status,
CASE
WHEN hcab_reviewid IS NULL THEN 0
ELSE 1
END AS HCAB
FROM htask ht
LEFT JOIN call_queue cq
ON ht.frn_callid = cq.frn_callid
LEFT JOIN hcab_review hr
ON hr.frn_callid = cq.frn_callid
AND ht.frn_leuserid = hr.frn_leuserid)
SELECT Isnull(frn_callid, 0) AS frn_callid,
Isnull(frn_hcatid, 0) AS frn_hcatid,
Isnull(HCAB, 0) AS HCAB,
Isnull(frn_hcat_optionid, 0) AS frn_hcat_optionid,
Isnull(frn_lskinid, 0) AS frn_lskinid,
Isnull(frn_leuserid, 0) AS frn_leuserid,
Isnull(status, 0) AS status,
Isnull(duration_seconds, 0) AS duration_seconds,
Isnull(add_path, '') AS add_path,
Isnull(htaskid, 0) AS htaskid
FROM cte
ORDER BY frn_callid
`)
if (req.recordset.length !== 0) {
console.log(req.recordset)
logger.info('returning query records')
return req.recordset
}
pool.close()
} catch (err) {
logger.error(err)
}
}
const insertRebase = async (data) => {
try {
sql.close()
let pool = await sql.connect(rbENV.SQL_CONFIG)
for (let i = 0; i < data.length; i++) {
console.log(data[i])
let req = await pool.request()
.input('frn_callid', sql.BigInt, data[i].frn_callid)
.input('frn_categoryid', sql.Int, data[i].frn_hcatid)
.input('HCAB', sql.Int, data[i].HCAB)
.input('frn_answer_optionid', sql.Int, data[i].frn_hcat_optionid)
.input('frn_leuserid', sql.Int, data[i].frn_leuserid)
.input('frn_lskinid', sql.Int, data[i].frn_lskinid)
.input('frn_statusid', sql.TinyInt, data[i].status)
.input('reviewid', sql.Int, data[i].htaskid)
.input('call_duration', sql.Int, data[i].duration_seconds)
.input('HCAB_trigger', sql.VarChar, data[i].add_path)
.query('SET IDENTITY_INSERT review ON; INSERT INTO review (frn_callid, frn_categoryid, HCAB, frn_answer_optionid, frn_leuserid, frn_lskinid, frn_statusid, reviewid, call_duration, HCAB_trigger) VALUES (@frn_callid, @frn_categoryid, @HCAB, @frn_answer_optionid, @frn_leuserid, @frn_lskinid, @frn_statusid, @reviewid, @call_duration, @HCAB_trigger)', function (err, recordset) {
if (err) {
logger.error(err)
console.log(err)
}
pool.close()
})
}
} catch (err) {
logger.error(err)
}
}
const initializeReview = async () => {
try {
const humData = await getReviewHumanatic()
insertRebase(humData)
} catch (err) {
console.log(err)
}
}
initializeReview()
我查看了这个问题NPM MSSQL - error: uncaughtException: Cannot read property 'release' of null但看起来没有确定的解决方案。
错误堆栈跟踪:
编辑:自从我的原始帖子以来,我已将插入查询转换为preparedstatement:
const insertRebase = async (data) => {
try {
sql.close()
let pool = await sql.connect(rbENV.SQL_CONFIG)
for (let i = 0; i < data.length; i++) {
let ps = new sql.PreparedStatement(pool)
ps.input('frn_callid', sql.BigInt)
ps.input('frn_categoryid', sql.Int)
ps.input('HCAB', sql.Int)
ps.input('frn_answer_optionid', sql.Int)
ps.input('frn_leuserid', sql.Int)
ps.input('frn_lskinid', sql.Int)
ps.input('frn_statusid', sql.TinyInt)
ps.input('reviewid', sql.Int)
ps.input('call_duration', sql.Int)
ps.input('HCAB_trigger', sql.VarChar)
ps.prepare(`SET IDENTITY_INSERT review ON; INSERT INTO review (frn_callid, frn_categoryid, HCAB, frn_answer_optionid, frn_leuserid, frn_lskinid, frn_statusid, reviewid, call_duration, HCAB_trigger) VALUES (@frn_callid, @frn_categoryid, @HCAB, @frn_answer_optionid, @frn_leuserid, @frn_lskinid, @frn_statusid, @reviewid, @call_duration, @HCAB_trigger)`, err => {
if (err) {
console.log(err)
logger.error(err)
} else {
ps.execute({frn_callid: data[i].frn_callid, frn_categoryid: data[i].frn_hcatid, HCAB: data[i].HCAB, frn_answer_optionid: data[i].frn_hcat_optionid, frn_leuserid: data[i].frn_leuserid, frn_lskinid: data[i].frn_lskinid, frn_statusid: data[i].status, reviewid: data[i].htaskid, call_duration: data[i].duration_seconds, HCAB_trigger: data[i].add_path}, (err, result) => {
if (err) {
console.log(err)
logger.error(err)
} else {
ps.unprepare(err => {
if (err) {
console.log(err)
logger.error(err)
}
})
}
})
}
})
}
} catch (err) {
logger.error(err)
}
}
我不确定为什么preparedstatement 解决方案比以前的解决方案有效,但是preparedstatement 解决方案似乎没有出错并正确插入所有记录。
至于 sql.close() 全局连接问题,做
const getReviewHumanatic = async () => {
try {
let pool1 = await sql.connect(SQL_CONFIG1)
let req = await pool1.request()
}
创建全局连接?我假设它正在创建本地连接,如果我这样做了
let pool2 = await sql.connect(SQL_CONFIG2)
它将创建一个单独的 sql 连接,但似乎并非如此,因为sql.close()
在创建 pool2 之前我无法运行该脚本。
我检查了 node-mssql 文档,看起来如果我在没有池规范的情况下执行请求,它将使用全局 sql 连接;也许这就是我的脚本正在发生的事情?https://www.npmjs.com/package/mssql#request