2017-08-01 1 views
0

Wie kann ich eine Zeile in der Datenbank und INSERT/UPDATE entsprechend zum Suchergebnis korrekt suchen (INSERT wenn nicht gefunden, UPDATE wenn gefunden)?Insert or Updated "Transaktionsabfrage bereits abgeschlossen"

ich dies derzeit tun:

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 }); 
      }); 

Und ich erhalte diesen Fehler:

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 Debug-Ausgabe

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 
+0

haben Sie die Umgebungsvariable wie gesagt versucht Einstellung: 'Export DEBUG = Knex: tx'? – flaviodesousa

Antwort

1

Wenn unter einer Transaktion ALL bezogenen Datenbank Zugriffe müssen im Kontext der Transaktion liegen.

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

Ihre Iterationen werden nicht korrekt promitifiziert. Das bewirkt, dass Ihre Änderungen den Transaktionskontext verlassen, wodurch der Fehler "Transaktionsabfrage ist bereits abgeschlossen" verursacht wird. Wenn Sie Versprechungen innerhalb einer Schleife erstellen, ist es immer ratsam, sie zu sammeln und an eine Verarbeitung von Versprechungssammlungen wie Promise.all() zu senden. Auf diese Weise wird vermieden, dass der Transaktionskontext verlassen wird, bevor alle Versprechen gelöst sind.

Diese Veränderungen können als unter einem Code führen (ungetestet):

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 }); 
    }); 
}; 
+0

Die Schleife soll eine CSV-Datei mit 20K Zeilen importieren. Wird es ein Problem sein, wenn ich der Sammlung 20K Versprechungen hinzufüge und sie alle gleichzeitig laufe? –

+0

Wenn ich in der Entwicklungsumgebung bin benutze ich SQLite und selbst wenn ich die Transaktion entferne, nachdem einige hundert Zeilen richtig eingefügt/UPDATEd wurde, bekommt es 'Knex: Timeout erwirbt eine Verbindung. Der Pool ist wahrscheinlich voll. –

+0

'Promise.all()' stellt nur sicher, dass alle Versprechen gelöst wurden. In der Tat, wenn Sie 'Promise.all()' mit 20K Updates aufrufen, ist es sehr wahrscheinlich, dass die meisten von ihnen bereits gelöst sind. Und wenn Ihre Transaktionen in der Regel aus 20K-Updates bestehen, müssen Sie möglicherweise Ihre Datenbank optimieren. – flaviodesousa

Verwandte Themen