如何在 node.js 中等待流式传输 sql 查询
How to await a streaming sql query in node.js
我需要调出一个运行 sql 查询的函数,具有行级功能,并在继续之前等待整个过程。
函数代码:
const sql = require('mssql')
exports.doit = ()=>{
const pool1 = new sql.ConnectionPool(dbConfig);
const pool1Connect = pool1.connect();
pool1.on('error', err => {
console.error('error occurred on pool')
})
await pool1Connect
try {
const request = pool1.request();
request.stream = true;
request.query('select * from dbo.user');
request.on('row', async orow => {
console.log('outer row');
const innerPool = new sql.ConnectionPool(dbConfig);
const innerConnection = innerPool.connect();
innerPool.on('error', err => {
console.error('error occurred on pool')
});
const iConnection = await innerConnection;
connections.push(iConnection);
const innerRequest = innerPool.request();
innerRequest.stream = true;
var iquery = 'select * from dbo.order where userId='+ orow.userId
innerRequest.query(iquery);
innerRequest.on('row', async irow => {
console.log(`User: ${orow.userId} Order: ${irow.orderId}`);
});
innerRequest.on('done', async () => {
console.log('inner done');
iConnection.close();
});
});
request.on('done', async () => {
console.log('outer done');
})
} catch (err) {
console.error('SQL error', err);
}
sql.on('error', err => {
// ... error handler
})
}
然后像这样调用上面的函数:
var doit = require('./testmeHandler.js').doit;
doit()
.then(()=>{
console.log("I AM DONE");
});
或
await doit();
console.log('I AM DONE');
你明白了...
但真正发生的是,函数被调用,然后是 'I AM DONE',然后是所有 sql 调用的结果。
有人可以帮我把 'I AM DONE' 放在底部吗?还在习惯 async/await 和承诺。
谢谢
不知怎的,我相信你把它搞得有点混乱了。
使用这个
exports.doit = async ()=>
{
const request = new sql.Request(conn)
let records = await request.query('select * from dbo.user')
records.forEach(async r=>{
try{
// do something
const inner = new sql.Request(conn)
let recordInner = await request.query(innerQuery)
recordInner.forEach(async r=>{//do some stuff})
inner.close()
}
catch(err){
//do something with the error
}
records.close()
})
}
执行:
async execute(){
const result = await doit()
return result
}
execute()
虽然我根本不知道你为什么要使用两个连接。只需尝试使用 JOIN
或 WHERE
子查询编写更明确的查询。您可以在单个查询中实现所有这些,而不是使用嵌套连接。 SQL虽然有点老,但是真的很给力
select * from dbo.order WHERE userId IN (SELECT userId FROM dbo.user)
对我来说更有意义。但是,无论你的船如何漂浮。
关于子查询的更多信息:https://www.dofactory.com/sql/subquery
在尝试让调用者同步工作一段时间后,我放弃并重新编写了使用常规查询(不是流式查询)的方法,并实现了我自己的 paging/throttling控制内存使用。现在效果很好!
我正在使用连接池来允许子查询和其他进程在一批结果中异步发生。
我会post更新代码。
我需要调出一个运行 sql 查询的函数,具有行级功能,并在继续之前等待整个过程。
函数代码:
const sql = require('mssql')
exports.doit = ()=>{
const pool1 = new sql.ConnectionPool(dbConfig);
const pool1Connect = pool1.connect();
pool1.on('error', err => {
console.error('error occurred on pool')
})
await pool1Connect
try {
const request = pool1.request();
request.stream = true;
request.query('select * from dbo.user');
request.on('row', async orow => {
console.log('outer row');
const innerPool = new sql.ConnectionPool(dbConfig);
const innerConnection = innerPool.connect();
innerPool.on('error', err => {
console.error('error occurred on pool')
});
const iConnection = await innerConnection;
connections.push(iConnection);
const innerRequest = innerPool.request();
innerRequest.stream = true;
var iquery = 'select * from dbo.order where userId='+ orow.userId
innerRequest.query(iquery);
innerRequest.on('row', async irow => {
console.log(`User: ${orow.userId} Order: ${irow.orderId}`);
});
innerRequest.on('done', async () => {
console.log('inner done');
iConnection.close();
});
});
request.on('done', async () => {
console.log('outer done');
})
} catch (err) {
console.error('SQL error', err);
}
sql.on('error', err => {
// ... error handler
})
}
然后像这样调用上面的函数:
var doit = require('./testmeHandler.js').doit;
doit()
.then(()=>{
console.log("I AM DONE");
});
或
await doit();
console.log('I AM DONE');
你明白了...
但真正发生的是,函数被调用,然后是 'I AM DONE',然后是所有 sql 调用的结果。
有人可以帮我把 'I AM DONE' 放在底部吗?还在习惯 async/await 和承诺。
谢谢
不知怎的,我相信你把它搞得有点混乱了。
使用这个
exports.doit = async ()=>
{
const request = new sql.Request(conn)
let records = await request.query('select * from dbo.user')
records.forEach(async r=>{
try{
// do something
const inner = new sql.Request(conn)
let recordInner = await request.query(innerQuery)
recordInner.forEach(async r=>{//do some stuff})
inner.close()
}
catch(err){
//do something with the error
}
records.close()
})
}
执行:
async execute(){
const result = await doit()
return result
}
execute()
虽然我根本不知道你为什么要使用两个连接。只需尝试使用 JOIN
或 WHERE
子查询编写更明确的查询。您可以在单个查询中实现所有这些,而不是使用嵌套连接。 SQL虽然有点老,但是真的很给力
select * from dbo.order WHERE userId IN (SELECT userId FROM dbo.user)
对我来说更有意义。但是,无论你的船如何漂浮。
关于子查询的更多信息:https://www.dofactory.com/sql/subquery
在尝试让调用者同步工作一段时间后,我放弃并重新编写了使用常规查询(不是流式查询)的方法,并实现了我自己的 paging/throttling控制内存使用。现在效果很好!
我正在使用连接池来允许子查询和其他进程在一批结果中异步发生。
我会post更新代码。