Knex返回检测到的死锁

时间:2019-05-09 08:10:06

标签: node.js postgresql express knex.js

所以我有此功能可以减少数据库的库存,问题是,如果我必须减去2个不同项目的数量,那么Knex将返回“ Deadlock Detected”,因此代码上出现了循环。

const updateOrder = (req, res, db, logger) => {
    let {
        status,
        trx_id,
        orNumber,
        returnReason
    } = req.body;
    db.transaction((trx) => {
            db('cart')
                .returning('*')
                .where('trx_id', '=', trx_id)
                .update({
                    status: status,
                    or_num: orNumber,
                    return_reason: returnReason
                })
                .then(order => {
                    if (status === 'Success') {
                        db('cart')
                            .returning('*')
                            .where('trx_id', '=', trx_id)
                            .update({
                                date_purchased: new Date()
                            })
                            .then(purchased => {
                                db.transaction((trx) => {
                                    db.select('*').from('cart_item').where({
                                            cart_id: order[0].id,
                                            trx_id: order[0].trx_id
                                        })
                                        .then(item => {
                                            let newQuantity = [];
                                            if (item[0]) {
                                                for (let i = 0; i < item.length; i++) {
                                                    db.select('*').from('product').where('item_code', '=', item[i].item_code)
                                                        .then(product => {
                                                            for (let ii = 0; ii < product.length; ii++) {
                                                                if (product[ii]) {
                                                                    newQuantity[ii] = parseInt(product[ii].stock) - parseInt(item[i].quantity)
                                                                    db('product')
                                                                        .returning('*')
                                                                        .where('item_code', '=', item[i].item_code)
                                                                        .update({
                                                                            stock: newQuantity[ii]
                                                                        })
                                                                        .then(stock => {
                                                                            if (stock[0]) {
                                                                                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
                                                                                    })
                                                                                    .then(activity => {
                                                                                        if (activity[0]) {
                                                                                            res.json({
                                                                                                isSuccess: true
                                                                                            });
                                                                                            return;
                                                                                        } else {
                                                                                            res.json({
                                                                                                isSuccess: false
                                                                                            });
                                                                                            return;
                                                                                        }
                                                                                    })
                                                                                    .then(trx.commit)
                                                                                    .catch(err => {
                                                                                        logger.error(err);
                                                                                        trx.rollback;
                                                                                        res.render('pages/error-500');
                                                                                    });
                                                                            }
                                                                        })
                                                                        .then(trx.commit)
                                                                        .catch(err => {
                                                                            logger.error(err);
                                                                            trx.rollback;
                                                                            res.render('pages/error-500');
                                                                        });
                                                                }
                                                            }
                                                        })
                                                        .then(trx.commit)
                                                        .catch(err => {
                                                            logger.error(err);
                                                            trx.rollback;
                                                            res.render('pages/error-500');
                                                        });
                                                }
                                            }
                                        })
                                        .then(trx.commit)
                                        .catch(err => {
                                            logger.error(err);
                                            trx.rollback;
                                            res.render('pages/error-500');
                                        });
                                    })
                                    .catch(err => logger.error(err));
                            })
                            .catch(err => logger.error(err));
                    } else if (status === 'Returned'){
                        if (order[0]) {
                            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,
                                    return_reason: returnReason
                                })
                                .then(activity => {
                                    if (activity[0]) {
                                        res.json({
                                            isSuccess: true
                                        });
                                        return;
                                    } else {
                                        res.json({
                                            isSuccess: false
                                        });
                                        return;
                                    }
                                })
                                .then(trx.commit)
                                .catch(err => {
                                    logger.error(err);
                                    trx.rollback;
                                    res.render('pages/error-500');
                                });
                        }
                    }
                    else {
                        if (order[0]) {
                            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
                                })
                                .then(activity => {
                                    if (activity[0]) {
                                        res.json({
                                            isSuccess: true
                                        });
                                        return;
                                    } else {
                                        res.json({
                                            isSuccess: false
                                        });
                                        return;
                                    }
                                })
                                .then(trx.commit)
                                .catch(err => {
                                    logger.error(err);
                                    trx.rollback;
                                    res.render('pages/error-500');
                                });
                        }
                    }
                })
                .then(trx.commit)
                .catch(err => {
                    logger.error(err);
                    trx.rollback;
                    res.render('pages/error-500');
                });
        })
        .catch(err => logger.error(err));
}

module.exports = {
    updateOrder
}

我对NodeJS还是很陌生,我知道我的代码中有一个承诺地狱,因为我无法将承诺兑现,因为我必须将前一个承诺的数据用于下一个承诺。

如果我只需要使用一个更新查询,代码就可以正常工作,但是当我不得不使用两个更新查询时,就会遇到死锁。

2 个答案:

答案 0 :(得分:1)

您应该从学习如何使用promisesasync/await开始,并对它们做一些更简单的事情。在处理诺言中有太多错误,使我失去了计数。实际上,您可以并行执行很多工作,而不必等待早先的查询准备就绪。

Knex is returning Deadlock Detected意味着您已经以一种同时锁定数据库执行的方式对数据库进行了查询。

答案 1 :(得分:0)

在许多研究的帮助下,我终于摆脱了死锁错误,并同时使代码变平。

这是工作代码:

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();
      // console.log(first);
      if(first[0].status == 'Success'){
        const second = await updateDate().catch(err => {
            throw err
        });
        // console.log(second); 
        const third = await selectItems(second[0]).catch(err => {
            throw err
        });
        // console.log(third);
        const fourth = await selectProduct(third).catch(err => {
            throw err
        });
        const fourth2 = [].concat(...fourth);
        // console.log(fourth2);
        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
}

我有一个新问题,特别是关于交易的问题,但是会发布到另一个问题中。