pg-promise transaction with dependent queries in forEach loop gives warning Error: Querying against a released or lost connection
pg-promise transaction with dependent queries in forEach loop gives warning Error: Querying against a released or lost connection
我正在尝试在 pg-promise 事务中插入链接数据。事务成功插入所有数据正确,但给出警告UnhandledPromiseRejectionWarning: Error: Querying against a released or lost connection.
。
导致这个的代码原来是:
const item = {
batch: { batch_number: 1 },
ingredients: [
{ amount: '12', unit: 'kg' },
{ amount: '4', unit: 'L' }
],
}
return await db.tx(async t => {
const batchQueryString = pgp.helpers.insert(item.batch, null, 'ionomer_batch')
const batchQuery = await t.one(batchQueryString + ' RETURNING ionomer_batch_id')
item.ingredients.forEach(async ingredient => {
const ingredientQueryString = pgp.helpers.insert(ingredient, null, 'ingredient')
const ingredientQuery = await t.one(ingredientQueryString + ' RETURNING ingredient_id')
await t.none(
`INSERT INTO ionomer_batch_step(ionomer_batch_id, ingredient_id)
VALUES(${batchQuery.ionomer_batch_id}, ${ingredientQuery.ingredient_id})`
)
})
return batchQuery
}).then(data => {
return {success: true, response: data}
}).catch(error => {
return {success: false, response: error}
})
我通过
让它在没有产生警告的情况下工作
return await db.tx(async t => {
const batchQueryString = pgp.helpers.insert(item.batch, null, 'ionomer_batch')
const batchQuery = await t.one(batchQueryString + ' RETURNING ionomer_batch_id')
const ingredientQueries = []
// this can't be async
item.ingredients.forEach(ingredient => {
const ingredientQueryString = pgp.helpers.insert(ingredient, null, 'ingredient')
const ingredientQuery = t.one(ingredientQueryString + ' RETURNING ingredient_id')
ingredientQueries.push(ingredientQuery)
})
const resolvedIngredientQueries = await t.batch(ingredientQueries)
resolvedIngredientQueries.forEach(async ingredientQuery => {
await t.none(
`INSERT INTO ionomer_batch_step(ionomer_batch_id, ingredient_id)
VALUES(${batchQuery.ionomer_batch_id}, ${ingredientQuery.ingredient_id})`
)
})
return batchQuery
}).then(data => {
return {success: true, response: data}
}).catch(error => {
return {success: false, response: error}
})
但我现在必须循环两次而不是一次,而且我在第一个循环中失去了异步。似乎应该有一种方法可以在接近第一次尝试时做一些事情,而不会发出有关已释放或丢失连接的警告。我试着链接查询,但无法让它工作。
正如@vitaly-t 所说,我需要确保 forEach 循环真正完成。
可行的解决方案是
const item = {
batch_number: 1,
},
ingredients: [
{ amount: '12', unit: 'kg' },
{ amount: '4', unit: 'L' }
],
}
return await db.tx(async t => {
const batchQueryString = pgp.helpers.insert(item.batch, null, 'ionomer_batch')
const batchQuery = await t.one(batchQueryString + ' RETURNING ionomer_batch_id')
await asyncForEach(item.ingredients, async ingredient => {
const ingredientQueryString = pgp.helpers.insert(ingredient, null, 'ingredient')
const ingredientQuery = await t.one(ingredientQueryString + ' RETURNING ingredient_id')
await t.none(
`INSERT INTO ionomer_batch_step(ionomer_batch_id, ingredient_id)
VALUES(${batchQuery.ionomer_batch_id}, ${ingredientQuery.ingredient_id})`
)
})
return batchQuery
}).then(data => {
return {success: true, response: data}
}).catch(error => {
return {success: false, response: error}
})
我必须在哪里创建辅助函数
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
如描述here
作为对@deanna 自己回答的补充...
你真的不需要实现循环。您可以将请求重新映射到承诺数组中,然后解决它:
await db.tx(async t => {
const batchQueryString = pgp.helpers.insert(item.batch, null, 'ionomer_batch');
const batchQuery = await t.one(`${batchQueryString} RETURNING ionomer_batch_id`);
const inserts = item.ingredients.map(async i => {
const query = pgp.helpers.insert(i, null, 'ingredient');
const ingredientQuery = await t.one(`${query} RETURNING ingredient_id`);
return t.none(
`INSERT INTO ionomer_batch_step(ionomer_batch_id, ingredient_id)
VALUES($/batchQuery.ionomer_batch_id/, $/ingredientQuery.ingredient_id/)`,
{batchQuery, ingredientQuery});
});
await t.batch(inserts); // settle all generated promises
return batchQuery;
});
另外,你可以从变化中看出,你不应该那样使用 ES6 值注入。 See here:
IMPORTANT: Never use the reserved ${}
syntax inside ES6 template strings, as those have no knowledge of how to format values for PostgreSQL. Inside ES6 template strings you should only use one of the 4 alternatives - $()
, $<>
, $[]
or $//
.
我正在尝试在 pg-promise 事务中插入链接数据。事务成功插入所有数据正确,但给出警告UnhandledPromiseRejectionWarning: Error: Querying against a released or lost connection.
。
导致这个的代码原来是:
const item = {
batch: { batch_number: 1 },
ingredients: [
{ amount: '12', unit: 'kg' },
{ amount: '4', unit: 'L' }
],
}
return await db.tx(async t => {
const batchQueryString = pgp.helpers.insert(item.batch, null, 'ionomer_batch')
const batchQuery = await t.one(batchQueryString + ' RETURNING ionomer_batch_id')
item.ingredients.forEach(async ingredient => {
const ingredientQueryString = pgp.helpers.insert(ingredient, null, 'ingredient')
const ingredientQuery = await t.one(ingredientQueryString + ' RETURNING ingredient_id')
await t.none(
`INSERT INTO ionomer_batch_step(ionomer_batch_id, ingredient_id)
VALUES(${batchQuery.ionomer_batch_id}, ${ingredientQuery.ingredient_id})`
)
})
return batchQuery
}).then(data => {
return {success: true, response: data}
}).catch(error => {
return {success: false, response: error}
})
我通过
让它在没有产生警告的情况下工作return await db.tx(async t => {
const batchQueryString = pgp.helpers.insert(item.batch, null, 'ionomer_batch')
const batchQuery = await t.one(batchQueryString + ' RETURNING ionomer_batch_id')
const ingredientQueries = []
// this can't be async
item.ingredients.forEach(ingredient => {
const ingredientQueryString = pgp.helpers.insert(ingredient, null, 'ingredient')
const ingredientQuery = t.one(ingredientQueryString + ' RETURNING ingredient_id')
ingredientQueries.push(ingredientQuery)
})
const resolvedIngredientQueries = await t.batch(ingredientQueries)
resolvedIngredientQueries.forEach(async ingredientQuery => {
await t.none(
`INSERT INTO ionomer_batch_step(ionomer_batch_id, ingredient_id)
VALUES(${batchQuery.ionomer_batch_id}, ${ingredientQuery.ingredient_id})`
)
})
return batchQuery
}).then(data => {
return {success: true, response: data}
}).catch(error => {
return {success: false, response: error}
})
但我现在必须循环两次而不是一次,而且我在第一个循环中失去了异步。似乎应该有一种方法可以在接近第一次尝试时做一些事情,而不会发出有关已释放或丢失连接的警告。我试着链接查询,但无法让它工作。
正如@vitaly-t 所说,我需要确保 forEach 循环真正完成。
可行的解决方案是
const item = {
batch_number: 1,
},
ingredients: [
{ amount: '12', unit: 'kg' },
{ amount: '4', unit: 'L' }
],
}
return await db.tx(async t => {
const batchQueryString = pgp.helpers.insert(item.batch, null, 'ionomer_batch')
const batchQuery = await t.one(batchQueryString + ' RETURNING ionomer_batch_id')
await asyncForEach(item.ingredients, async ingredient => {
const ingredientQueryString = pgp.helpers.insert(ingredient, null, 'ingredient')
const ingredientQuery = await t.one(ingredientQueryString + ' RETURNING ingredient_id')
await t.none(
`INSERT INTO ionomer_batch_step(ionomer_batch_id, ingredient_id)
VALUES(${batchQuery.ionomer_batch_id}, ${ingredientQuery.ingredient_id})`
)
})
return batchQuery
}).then(data => {
return {success: true, response: data}
}).catch(error => {
return {success: false, response: error}
})
我必须在哪里创建辅助函数
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
如描述here
作为对@deanna 自己回答的补充...
你真的不需要实现循环。您可以将请求重新映射到承诺数组中,然后解决它:
await db.tx(async t => {
const batchQueryString = pgp.helpers.insert(item.batch, null, 'ionomer_batch');
const batchQuery = await t.one(`${batchQueryString} RETURNING ionomer_batch_id`);
const inserts = item.ingredients.map(async i => {
const query = pgp.helpers.insert(i, null, 'ingredient');
const ingredientQuery = await t.one(`${query} RETURNING ingredient_id`);
return t.none(
`INSERT INTO ionomer_batch_step(ionomer_batch_id, ingredient_id)
VALUES($/batchQuery.ionomer_batch_id/, $/ingredientQuery.ingredient_id/)`,
{batchQuery, ingredientQuery});
});
await t.batch(inserts); // settle all generated promises
return batchQuery;
});
另外,你可以从变化中看出,你不应该那样使用 ES6 值注入。 See here:
IMPORTANT: Never use the reserved
${}
syntax inside ES6 template strings, as those have no knowledge of how to format values for PostgreSQL. Inside ES6 template strings you should only use one of the 4 alternatives -$()
,$<>
,$[]
or$//
.