2017-08-01 116 views
0

如何根據搜索結果正確搜索數據庫中的某一行以及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 
+0

你試過設置環境變量聲明:'出口DEBUG = knex:tx'? – flaviodesousa

回答

1

當一個事務ALL相關的數據庫下訪問必須在交易的範圍內。

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

您的迭代沒有正確promisified。這會使您的更改轉義事務上下文,導致「事務查詢已完成」錯誤。在循環中創建承諾時,始終建議收集承諾並提交承諾收集處理,例如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 }); 
    }); 
}; 
+0

循環是導入一個具有20K行的CSV文件。如果我向集合中添加20K承諾並同時運行所有這些承諾,會不會有問題? –

+0

當我在開發環境中使用SQLite時,即使我刪除了事務,在正確插入/更新了幾百行之後,它也會獲取'Knex:Timeout獲取連接。游泳池可能已經滿了。 –

+0

'Promise.all()'只確保所有的承諾都已解決。事實上,當你用20K的更新調用'Promise.all()'時,很可能大部分已經解決了。而且,如果您的交易通常包含20K更新,則可能需要調整數據庫。 – flaviodesousa