插入或更新获取 "Transaction query already complete"

Insert or Updated getting "Transaction query already complete"

如何正确地在数据库中搜索一行,并根据搜索结果INSERT/UPDATEINSERT如果没有找到,UPDATE如果找到)?

我目前正在这样做:

bookshelf.transaction(async function (t) {
            for (var x = 0; x < 10; x++) {
                let row = pmsParser.getRow(x);
                if (_.isEmpty(row)) {
                    break;
                }

                let data = {
                    lastUpdate: moment(row.lastUpdate, 'DD/MM/YYYY - HH:mm').toDate(),
                    mvs: row.version,
                    color: row.color,
                    location: row.location,
                    status: row.status
                };

                new Vehicle({ chassi: row.chassi })
                    .fetch({ require: true })
                    .then(model => {

                        return new Vehicle(model)
                            .save(data, { transacting: t, patch: true });

                    })
                    .catch(Vehicle.NotFoundError, err => {
                        new Vehicle(data)
                            .save('chassi', row.chassi, { transacting: t })
                            .then(() => {
                                console.log(`Inserted... ${row.chassi}`);
                            });
                    })
                    .catch(err => {
                        console.log(err.message);
                    });
            }
        })
            .catch(function (err) {
                console.error(err);
                return res.json({ status: false, count: 0, error: err.message });
            });

我收到此错误:

Transaction query already complete, run with DEBUG=knex:tx for more info
Unhandled rejection Error: Transaction query already complete, run with DEBUG=knex:tx for more info
    at completedError (/home/node/app/node_modules/knex/lib/transaction.js:297:9)
    at /home/node/app/node_modules/knex/lib/transaction.js:266:22
    at tryCatcher (/home/node/app/node_modules/bluebird/js/release/util.js:16:23)
    at Function.Promise.attempt.Promise.try (/home/node/app/node_modules/bluebird/js/release/method.js:39:29)
    at Client_SQLite3.trxClient.query (/home/node/app/node_modules/knex/lib/transaction.js:264:34)
    at Runner.<anonymous> (/home/node/app/node_modules/knex/lib/runner.js:138:36)
    at Runner.tryCatcher (/home/node/app/node_modules/bluebird/js/release/util.js:16:23)
    at Runner.query (/home/node/app/node_modules/bluebird/js/release/method.js:15:34)
    at /home/node/app/node_modules/knex/lib/runner.js:61:21
    at tryCatcher (/home/node/app/node_modules/bluebird/js/release/util.js:16:23)
    at /home/node/app/node_modules/bluebird/js/release/using.js:185:26
    at tryCatcher (/home/node/app/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/home/node/app/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/home/node/app/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/home/node/app/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/home/node/app/node_modules/bluebird/js/release/promise.js:693:18)

Knex 调试输出

  knex:tx trx1: Starting top level transaction +0ms
  knex:tx trx1: releasing connection +28ms
  knex:tx undefined: Transaction completed: update "vehicles" set "color" = ?, "lastUpdate" = ?, "location" = ?, "mvs" = ?, "status" = ? where "id" = ? +15ms
Transaction query already complete, run with DEBUG=knex:tx for more info
  knex:tx undefined: Transaction completed: update "vehicles" set "color" = ?, "lastUpdate" = ?, "location" = ?, "mvs" = ?, "status" = ? where "id" = ? +8ms
Transaction query already complete, run with DEBUG=knex:tx for more info

在事务下所有 相关的数据库访问必须在事务的上下文中。

//...
new Vehicle({ chassi: row.chassi })
    .fetch({ require: true, transacting: t })
    .then(model => {
//...

您的迭代没有得到正确的承诺。这会使您的更改转义事务上下文,从而导致 'Transaction query already complete' 错误。在循环中创建承诺时,始终建议收集它们并提交给承诺集合处理,例如 Promise.all()。这将避免在解决所有承诺之前转义事务上下文。

这些更改可能会导致如下代码(未测试):

bookshelf.transaction(async function (t) {
  let promises = [];
  for (var x = 0; x < 10; x++) {
    let row = pmsParser.getRow(x);
    if (_.isEmpty(row)) {
      break;
    }
    let data = {
      lastUpdate: moment(row.lastUpdate, 'DD/MM/YYYY - HH:mm').toDate(),
      mvs: row.version,
      color: row.color,
      location: row.location,
      status: row.status
    };
    promises.push(
      new Vehicle({ chassi: row.chassi })
        .fetch({ require: true, transacting: t })
        .then(model => {
          return model // no need to use 'new Vehicle()' here
            .save(data, { transacting: t, patch: true });
        })
        .catch(Vehicle.NotFoundError, err => {
          return new Vehicle(data) // missing 'return'
            .save('chassi', row.chassi, { transacting: t })
            .then(() => {
               console.log(`Inserted... ${row.chassi}`);
            });
        })
        .catch(err => {
          console.log(err.message);
          // throw err; // should rethrow it!
        })
    );
  }
  return Promise.all(promises)
    .catch(function (err) {
       console.error(err);
       return res.json({ status: false, count: 0, error: err.message });
    });
};