数据库事务并行发生而不是在循环中顺序发生

Database transactions happen parallely instead of sequentially in loop

我有一个端点,它循环遍历数组并按如下方式更新数据库。

 app.post('/create', Authenticate, async (req, res) => {
  const {
    products,
  } = req.body;
  const trxProvider = knex.transactionProvider();
  const trx = await trxProvider();

  try {
    const formattedProduct = await Promise.all(products.map(async (product) => {

     // Get Current value
      const warehouseProducts = await trx('warehouse_products')
        .select('available_qty as qty')
        .where('product_code', product.product.code)
        .first();

      const finalQty = warehouseProducts.qty - product.orderQty;

     // Update database
      await trx('warehouse_products')
        .update({ available_qty: finalQty })
        .where('product_code', product.product.code);
    }));
    await trx('ordered_products')
      .insert(formattedProduct);
    trx.commit();
    console.log('Transaction successful');
    return send(res, 201, { success: true });
  } catch (err) {
    console.log(err);
    trx.rollback();
    const errors = {};
    errors.message = 'something went wrong';
    return send(res, 500, errors);
  }
});

当我尝试在循环中更新 warehouse_products table 的同一行时出现问题。 在循环中,最初 qty 值取自特定产品的 warehouse_products table,然后进行算术运算,qty 值已更新。

理想情况下,如果两次迭代都访问同一行,则第二次迭代的初始 qty 值应该是第一次迭代更新的值。然而,问题是第二次迭代也是从第一次迭代的初始值开始的。就好像这两个迭代是并行发生的,而不是顺序发生的。

因为您使用的是 Promise.all,所以它应该是并行发生的。对于顺序处理,更改此代码

await Promise.all(products.map(async (product) => {
// logic here
});

for(const product of products) {
  // logic here
}

查看 Promise.all()

的定义

It is typically used after having started multiple asynchronous tasks to run concurrently and having created promises for their results, so that one can wait for all the tasks being finished.

如果您不想使用 BluebirdAsync

这样的外部库

您可以使用简单的 for 循环,如下所示

let delay = (t) => new Promise((resolve) => {
 setTimeout(() => {
  return resolve(new Date().getMilliseconds())
 }, t*1000);
});

let array = [1,1,1,1];

//using simple for loop
async function test() {
 let out = [];
 for (let i = 0; i < 4; i++) {
  const res = await delay(array[i]);
  out.push(res);
 }
 return out;
}

test().then(res => {
 console.log(res)
})