mysql 节点的多个事务

Multiple Transactions in mysql for Node

我正在为 mysql 使用节点的驱动程序并且需要一个接一个而不是同时执行 'n' 个事务。

我试过使用 for/forEach 循环,但事务似乎是同时发生的,这导致我的 api 到 crash.Here 的错误:-

throw err; // Rethrow non-MySQL errors
      ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

单笔交易似乎工作得很好。

每个事务有4个查询,req.body是一个对象数组:-

router.post('/production/add', (req, res) => {
    for (const obj of req.body) {
        pool.getConnection(function (err, connection) {
            connection.beginTransaction(function (err) {
                if (err) throw err;

                const query1 = `select qty from production where prc_id = ${obj.prc_id}`;
                console.log(query1);
                connection.query(query1, function (error, result1, fields) {
                    if (error) {
                        return connection.rollback(function () {
                            res.status(400).send({ query: 1, message: error.sqlMessage, code: error.code, errno: error.errno });
                            return;
                        });
                    }
                    const new_prod_qty = result1[0].qty - obj.auth_prod_qty;
                    const query2 = new_prod_qty > 0 ? `update production set qty = ${new_prod_qty} where prc_id = ${obj.prc_id}` : `delete from production where prc_id = ${obj.prc_id}`;
                    console.log(query2);
                    connection.query(query2, function (error, results2, fields) {
                        if (error) {
                            return connection.rollback(function () {
                                res.status(400).send({ message: error.sqlMessage, code: error.code, errno: error.errno });
                                return;
                            });
                        }
                        const query3 = `update prc set auth_prod_qty = ${obj.auth_prod_qty} where prc_id = ${obj.prc_id}`;
                        console.log(query3);
                        connection.query(query3, function (error, results3, fields) {
                            if (error) {
                                return connection.rollback(function () {
                                    res.status(400).send({ message: error.sqlMessage, code: error.code, errno: error.errno });
                                    return;
                                });
                            }
                            const query4 = "select * from store";
                            connection.query(query4, function (error, results3, fields) {
                                if (error) {
                                    return connection.rollback(function () {
                                        res.status(400).send({ message: error.sqlMessage, code: error.code, errno: error.errno });
                                        return;
                                    });
                                }
                                connection.commit(function (err) {
                                    if (err) {
                                        return connection.rollback(function () {
                                            res.status(400).send({ message: error.sqlMessage, code: error.code, errno: error.errno });
                                            return;
                                        });
                                    }
                                    res.status(201).send(results2);
                                });
                            });
                        });
                    });
                });
            });
        });
    };
});

根据一些研究,Sequelize ORM 似乎可以保证交易,但我希望将其用作最后的手段。任何有或没有 Sequelize 的解决方案都将不胜感激!

提前致谢!

您需要按顺序使用 async / await 到 运行 您的交易。如何做到这一点?

当您 require('mysql2/promise') 时使用 API 的 npm mysql2 in place of npm mysql. That gets you promisified (awaitable) versions。此外,与那些糟糕的嵌套回调相比,编程和调试 有趣。只是不要忘记 awaits.

将此基本大纲用于代码的数据处理循环。一切都会按顺序进行。创建池的方式略有不同;阅读 npm 页面。这是未调试的。

const mysql = require('mysql2/promise');

router.post('/production/add', async (req, res) => {
  const connection = await pool.getConnection()

  for (const obj of req.body) {
    try {
      await connection.beginTransaction()
      const query1 = 'whatever'
      const result1 = await connection.query(query1)
      const query2 = 'something else'
      const result 2 = await connection.query(query2)
      /* etcetera etcetera */
      await connection.commit()
    } 
    catch (error) {
      await connection.rollback()
      pool.releaseConnection()
      res.status(400).send({ something })
    }
  }
  pool.releaseConnection()
}

mysql2/promise 正是我正在寻找的包,与 mysql 一起使用并使用 promise() 方法将 mysql 连接升级到基于承诺的 mysql2连接。

router.post('/stock/add', async (req, res) => {
    const connection = pool.getConnection(async function (err, connection) {
        if (err) {
            connection.release();
            res.status(400).send(err);
            return;
        }
        else {
            for (const obj of req.body) {
                try {
                    await connection.promise().beginTransaction();
                    const [result1, fields1] = await connection.promise().query(query1)
                    const [result2, fields2] = await connection.promise().query(query2);
                    const [result3, fields3] = await connection.promise().query(query3);
                    const [result4, fields4] = await connection.promise().query(query4);
                    await connection.promise().commit();
                }
                catch (error) {
                    await connection.promise().rollback();
                    connection.release();
                    res.status(400).send(error);
                    return;
                }
            }
            res.status(200).send('Transaction Complete');
        }
    });
});