Search code examples
knex.js

knex multiple operations, one one after another, inside a transaction


I need to run multiple operations against the database and I need to fit them all into a transaction. Here is how I do things and from my testing it does not seem to be right.

Basically for each operation I have a function that returns the knex promise. Based on the parameter, there may be no need to actually do anything, for instance, if there are not any rows to insert, I don't need to do anything

function insertRows(rowsToInsert, trx){
  if (rowsToInsert && rowsToInsert.length>0){
     return knex.batchInsert(...).transacting(trx) 
  }else{
    //no need to run
    return Promise.resolve() //this is probably wrong
  }
}

//I am returning a promise as I yield this function in a co

function process(params){
  return new Promise(function (resolve, reject){

    knex.transaction(function(trx){
       return insertRows(rows, trx)
      .then(function (result){
          return insertRows(rows2,trx)
       }).then(function (result){
          return updateRows(rows3,trx)
       })
    }
  }
}

Running in this way I have noticed that sometimes I can get a deadlock between one update and one insert so that makes me believe that my operations don't happen one after another but maybe in parallel? How should I handle:

  • multiple operations in one transaction
  • handle then() when rows is empty so just skip to the next then()

Solution

  • In agreement with @Mikael , you don't need the new Promise, but also I think you need to return knex.transaction(, so that that the transaction function is completed before additional processing is done?

    function process(params){
      return knex.transaction(function(trx){
            return insertRows(rows, trx)
        }).then(function (result){
            return insertRows(rows2,trx)
        }).then(function (result){
          return updateRows(rows3,trx)
        });
    }
    

    Since you didn't return knex.transaction(), this operation will be 'disconnected' from the caller's sequence, running asynchronously.

    Your return Promise.resolve() //this is probably wrong is fine. You are returning a resolved promise in the else, just like in the if portion of the function. Because that (sub)function is only called within a Promise ... .then, you could actually omit the else clause, because the .then statement automatically converts synchronous function return values into resolved promises.