使KnexJS Transactions与async/await一起使用 [英] Make KnexJS Transactions work with async/await

查看:68
本文介绍了使KnexJS Transactions与async/await一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使事务与async/await和knexjs一起工作,但无济于事.

代码(摘录是为了缩短帖子):

 const updateOrder = (req, res, db, logger) => {
  let {
    status,
    trx_id,
    orNumber,
    returnReason
  } = req.body;

  const updateStatus = () => {
    return db('cart')
      .returning('*')
      .where('trx_id', '=', trx_id)
      .update({
        status: status,
        or_num: orNumber,
        return_reason: returnReason
      });
  }

  const updateDate = () => {
    return db('cart')
      .returning('*')
      .where('trx_id', '=', trx_id)
      .update({
        date_purchased: new Date()
      });
  }

  const selectItems = (order) => {
    return db
      .select('*')
      .from('cart_items')
      .where({
        cart_id: order.id,
        trx_id: order.trx_id
      });
  }

  const selectProduct = (item) => {
    const queries = [];
    item.forEach(item => {
      const query = db.select('*')
        .from('product')
        .where('item_code', '=', item.item_code);
      queries.push(query);
    })
    return Promise.all(queries);
  }

  const updateQuantity = (product, cart) => {
    const prodQuantity = product.map(product => parseInt(product.stock));
    const cartQuantity = cart.map(cart => parseInt(cart.quantity));
    const newQuantity = [];
    const queries = [];
    for (let i = 0; i < product.length; i++) {
      newQuantity.push(prodQuantity[i] - cartQuantity[i]);
    }
    cart.map((cart, index) => {
      const query = db('products')
        .returning('*')
        .where('item_code', '=', cart.item_code)
        .update({
          stock: newQuantity[index]
        })
      queries.push(query);
    })
    return queries;
  }

  const updateLogs = () => {
    return db('activity_order_logs')
      .returning('*')
      .insert({
        date: new Date(),
        employee_id: req.session.emp_id,
        module: "MONITORING",
        trx_id: trx_id,
        activity: status,
        or_num: orNumber
      })
  }

  const sendResponse = (result) => {
    if (result) {
      res.json({
        isSuccess: true
      });
      return;
    } else {
      res.json({
        isSuccess: false
      });
      return;
    }
  }

  (async() => {
    const first = await updateStatus();

    if (first[0].status == 'Success') {
      const second = await updateDate().catch(err => {
        throw err
      });

      const third = await selectItems(second[0]).catch(err => {
        throw err
      });

      const fourth = await selectProduct(third).catch(err => {
        throw err
      });
      const fourth2 = [].concat(...fourth);

      const fifth = await updateQuantity(fourth2, third)
      const decreaseStock = async() => {
        const finalResult = [];
        for (let i = 0; i < fifth.length; i++) {
          const finalQuery = await Promise.resolve(fifth[i]);
          finalResult.push(finalQuery);
        }
        return finalResult;
      };

      const result = await decreaseStock().catch(err => {
        throw err
      });
      const result2 = [].concat(...result);
      const logs = await updateLogs().catch(err => {
        throw err
      });
      const sendRes = await sendResponse(logs);

    } else if (first[0].status == 'Returned') {
      const logs = await updateLogs().catch(err => {
        throw err
      });
      const sendRes = await sendResponse(logs);
    } else {
      const logs = await updateLogs().catch(err => {
        throw err
      });
      const sendRes = await sendResponse(logs);
    }
  })().catch(err => {
    console.log(err);
    res.json({
      isSuccess: false
    })
  });
}

module.exports = {
  updateOrder
} 

我尝试过的事情:

首次尝试-错误,返回交易被拒绝,没有错误

 //knex is initialized as db
const createTransaction = () => {
  return new Promise((resolve) => {
    return db.transaction(resolve);
  });
};

(async() => {
  const trx = await createTransaction();
  const first = await updateStatus();

  if (first[0].status == 'Success') {
    const second = await updateDate().catch(err => {
      throw err
    });
	
    const third = await selectItems(second[0]).catch(err => {
      throw err
    });

    const fourth = await selectProduct(third).catch(err => {
      throw err
    });
    const fourth2 = [].concat(...fourth);

    const fifth = await updateQuantity(fourth2, third)
    const decreaseStock = async() => {
      const finalResult = [];
      for (let i = 0; i < fifth.length; i++) {
        const finalQuery = await Promise.resolve(fifth[i]);
        finalResult.push(finalQuery);
      }
      return finalResult;
    };

    const result = await decreaseStock().catch(err => {
      throw err
    });
    const result2 = [].concat(...result);
    const logs = await updateLogs().catch(err => {
      throw err
    });
    const sendRes = await sendResponse(logs);

  } else if (first[0].status == 'Returned') {
    const logs = await updateLogs().catch(err => {
      throw err
    });
    const sendRes = await sendResponse(logs);
  } else {
    const logs = await updateLogs().catch(err => {
      throw err
    });
    const sendRes = await sendResponse(logs);
  }

  trx.commit();

})().catch(err => {
  trx.rollback();
  console.log(err);
  res.json({
    isSuccess: false
  })
}); 

第二次尝试-结果:即使存在故意的错误,事务仍会提交并且没有回滚.

 //knex is initalized as db
(async() => {
  try {
    return await db.transaction(async trx => {
      const first = await updateStatus();

      if (first[0].status == 'Success') {
        const second = await updateDate().catch(err => {
          throw err
        });

        const third = await selectItems(second[0]).catch(err => {
          throw err
        });

        const fourth = await selectProduct(third).catch(err => {
          throw err
        });
        const fourth2 = [].concat(...fourth);

        const fifth = await updateQuantity(fourth2, third)
        const decreaseStock = async() => {
          const finalResult = [];
          for (let i = 0; i < fifth.length; i++) {
            const finalQuery = await Promise.resolve(fifth[i]);
            finalResult.push(finalQuery);
          }
          return finalResult;
        };

        const result = await decreaseStock().catch(err => {
          throw err
        });
        const result2 = [].concat(...result);
        const logs = await updateLogs().catch(err => {
          throw err
        });
        const sendRes = await sendResponse(logs);

      } else if (first[0].status == 'Returned') {
        const logs = await updateLogs().catch(err => {
          throw err
        });
        const sendRes = await sendResponse(logs);
      } else {
        const logs = await updateLogs().catch(err => {
          throw err
        });
        const sendRes = await sendResponse(logs);
      }
    })
  } catch (err) {
    console.log(err);
    res.json({
      isSuccess: false
    })
  }
}) 

解决方案

看起来您正在创建事务,但是您没有向它发送任何查询,而是向knex的连接池中的其他数据库连接发送了查询.

这是通过knex使用事务的方式:

async () {
  try {
    const trxResult = await db.transaction(async (trx) => {
      const queryResult = await trx('table').where(... etc. ...);
      // do some more queries to trx
    });
    console.log("transaction was committed");
  } catch (e) {
    console.log("transaction was rolled back");
  }
}

此外,在将问题发布到stackoverflow之前,您还应尝试将代码量减少到最少.隐藏太多代码片段根本无济于事.

I'm trying to make transactions work with async/await and knexjs but to no avail.

The code (snippet is for the sake of shortening the post):

const updateOrder = (req, res, db, logger) => {
  let {
    status,
    trx_id,
    orNumber,
    returnReason
  } = req.body;

  const updateStatus = () => {
    return db('cart')
      .returning('*')
      .where('trx_id', '=', trx_id)
      .update({
        status: status,
        or_num: orNumber,
        return_reason: returnReason
      });
  }

  const updateDate = () => {
    return db('cart')
      .returning('*')
      .where('trx_id', '=', trx_id)
      .update({
        date_purchased: new Date()
      });
  }

  const selectItems = (order) => {
    return db
      .select('*')
      .from('cart_items')
      .where({
        cart_id: order.id,
        trx_id: order.trx_id
      });
  }

  const selectProduct = (item) => {
    const queries = [];
    item.forEach(item => {
      const query = db.select('*')
        .from('product')
        .where('item_code', '=', item.item_code);
      queries.push(query);
    })
    return Promise.all(queries);
  }

  const updateQuantity = (product, cart) => {
    const prodQuantity = product.map(product => parseInt(product.stock));
    const cartQuantity = cart.map(cart => parseInt(cart.quantity));
    const newQuantity = [];
    const queries = [];
    for (let i = 0; i < product.length; i++) {
      newQuantity.push(prodQuantity[i] - cartQuantity[i]);
    }
    cart.map((cart, index) => {
      const query = db('products')
        .returning('*')
        .where('item_code', '=', cart.item_code)
        .update({
          stock: newQuantity[index]
        })
      queries.push(query);
    })
    return queries;
  }

  const updateLogs = () => {
    return db('activity_order_logs')
      .returning('*')
      .insert({
        date: new Date(),
        employee_id: req.session.emp_id,
        module: "MONITORING",
        trx_id: trx_id,
        activity: status,
        or_num: orNumber
      })
  }

  const sendResponse = (result) => {
    if (result) {
      res.json({
        isSuccess: true
      });
      return;
    } else {
      res.json({
        isSuccess: false
      });
      return;
    }
  }

  (async() => {
    const first = await updateStatus();

    if (first[0].status == 'Success') {
      const second = await updateDate().catch(err => {
        throw err
      });

      const third = await selectItems(second[0]).catch(err => {
        throw err
      });

      const fourth = await selectProduct(third).catch(err => {
        throw err
      });
      const fourth2 = [].concat(...fourth);

      const fifth = await updateQuantity(fourth2, third)
      const decreaseStock = async() => {
        const finalResult = [];
        for (let i = 0; i < fifth.length; i++) {
          const finalQuery = await Promise.resolve(fifth[i]);
          finalResult.push(finalQuery);
        }
        return finalResult;
      };

      const result = await decreaseStock().catch(err => {
        throw err
      });
      const result2 = [].concat(...result);
      const logs = await updateLogs().catch(err => {
        throw err
      });
      const sendRes = await sendResponse(logs);

    } else if (first[0].status == 'Returned') {
      const logs = await updateLogs().catch(err => {
        throw err
      });
      const sendRes = await sendResponse(logs);
    } else {
      const logs = await updateLogs().catch(err => {
        throw err
      });
      const sendRes = await sendResponse(logs);
    }
  })().catch(err => {
    console.log(err);
    res.json({
      isSuccess: false
    })
  });
}

module.exports = {
  updateOrder
}

What I've tried:

First Try - Error, returns Transaction rejected with non-error

//knex is initialized as db
const createTransaction = () => {
  return new Promise((resolve) => {
    return db.transaction(resolve);
  });
};

(async() => {
  const trx = await createTransaction();
  const first = await updateStatus();

  if (first[0].status == 'Success') {
    const second = await updateDate().catch(err => {
      throw err
    });
	
    const third = await selectItems(second[0]).catch(err => {
      throw err
    });

    const fourth = await selectProduct(third).catch(err => {
      throw err
    });
    const fourth2 = [].concat(...fourth);

    const fifth = await updateQuantity(fourth2, third)
    const decreaseStock = async() => {
      const finalResult = [];
      for (let i = 0; i < fifth.length; i++) {
        const finalQuery = await Promise.resolve(fifth[i]);
        finalResult.push(finalQuery);
      }
      return finalResult;
    };

    const result = await decreaseStock().catch(err => {
      throw err
    });
    const result2 = [].concat(...result);
    const logs = await updateLogs().catch(err => {
      throw err
    });
    const sendRes = await sendResponse(logs);

  } else if (first[0].status == 'Returned') {
    const logs = await updateLogs().catch(err => {
      throw err
    });
    const sendRes = await sendResponse(logs);
  } else {
    const logs = await updateLogs().catch(err => {
      throw err
    });
    const sendRes = await sendResponse(logs);
  }

  trx.commit();

})().catch(err => {
  trx.rollback();
  console.log(err);
  res.json({
    isSuccess: false
  })
});

Second Try - Result: Transaction still commits and did not rolled back even though there's an intentional error.

//knex is initalized as db
(async() => {
  try {
    return await db.transaction(async trx => {
      const first = await updateStatus();

      if (first[0].status == 'Success') {
        const second = await updateDate().catch(err => {
          throw err
        });

        const third = await selectItems(second[0]).catch(err => {
          throw err
        });

        const fourth = await selectProduct(third).catch(err => {
          throw err
        });
        const fourth2 = [].concat(...fourth);

        const fifth = await updateQuantity(fourth2, third)
        const decreaseStock = async() => {
          const finalResult = [];
          for (let i = 0; i < fifth.length; i++) {
            const finalQuery = await Promise.resolve(fifth[i]);
            finalResult.push(finalQuery);
          }
          return finalResult;
        };

        const result = await decreaseStock().catch(err => {
          throw err
        });
        const result2 = [].concat(...result);
        const logs = await updateLogs().catch(err => {
          throw err
        });
        const sendRes = await sendResponse(logs);

      } else if (first[0].status == 'Returned') {
        const logs = await updateLogs().catch(err => {
          throw err
        });
        const sendRes = await sendResponse(logs);
      } else {
        const logs = await updateLogs().catch(err => {
          throw err
        });
        const sendRes = await sendResponse(logs);
      }
    })
  } catch (err) {
    console.log(err);
    res.json({
      isSuccess: false
    })
  }
})

解决方案

Looks like you are creating transaction, but then you are not sending any queries to it, but send queries to the other database connections in knex's connection pool.

This is how you should use transactions with knex:

async () {
  try {
    const trxResult = await db.transaction(async (trx) => {
      const queryResult = await trx('table').where(... etc. ...);
      // do some more queries to trx
    });
    console.log("transaction was committed");
  } catch (e) {
    console.log("transaction was rolled back");
  }
}

Also you should try reduce amount of code to minimum before posting problems to stackoverflow. Hiding too much code to snippets doesn't help at all.

这篇关于使KnexJS Transactions与async/await一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆