pg-promise事务在forEach循环中的依赖性查询给出了错误警告。对一个已释放或丢失的连接进行查询

问题描述 投票:0回答:1

我试图在一个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}
})

但我现在必须循环两次而不是一次,而且我在第一次循环中失去了异步。似乎应该有一种方法来做一些接近第一次尝试的事情,而不会遇到释放或丢失连接的警告。我玩了一下链式查询,但没能成功。

javascript node.js transactions pg-promise
1个回答
0
投票

作为对 @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的值注入。请看这里:

重要提示:切勿使用保留的 ${} 语法,因为这些语法对PostgreSQL的格式化值没有任何了解。在ES6模板字符串中,你应该只使用4种选择之一------。$(), $<>, $[]$//.


0
投票

正如@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);
  }
}

如上所述 此处

© www.soinside.com 2019 - 2024. All rights reserved.