Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knex Transaction with Promises

I am getting the correct output, and indeed, these two operations are being treated as a single transactional unit; where if one fails, both fail.

In this code example: i am doing a transaction of

(1) insert (2) update

The way I approach it is to nest my db operations inside the .then. My question is if this code is correct by accident? i am new to promises and knex.

knex.transaction(function(t) {
   knex('foo')
   .transacting(t)
   .insert({id:"asdfk", username:"barry", email:"[email protected]"})
   .then(function() {
       knex('foo')
       .where('username','=','bob')
       .update({email:"[email protected]"})
       .then(t.commit, t.rollback)
   })
})
.then(function() {
 // it worked
},
function() {
 // it failed
});

This works, but I feel like I am doing something wrong still. Looking for comments.

like image 916
david Avatar asked Apr 09 '14 08:04

david


People also ask

What happens if a transaction fails in KNEX?

Any failure will mean the database will rollback any queries executed on that connection to the pre-transaction state. Transactions are handled by passing a handler function into knex.transaction. The handler function accepts a single argument, an object which may be used in two ways:

How do I handle a transaction in KEX?

Transactions are handled by passing a handler function into knex.transaction. The handler function accepts a single argument, an object which may be used in two ways: As an object passed into a query with and eventually call commit or rollback.

What happens if a promise is not returned from the handler?

Notice that if a promise is not returned within the handler, it is up to you to ensure trx.commit, or trx.rollback are called, otherwise the transaction connection will hang. Calling trx.rollback will return a rejected Promise.


1 Answers

You need to return a promise from the inner query in order for the outer chain to be chained with that.

You also swallow any errors because you don't rethrow them - it's better to use .catch() for this reason because it makes it more clearer what is happening - that is what would happen with normal try-catch statement.

knex.transaction(function(t) {
   return knex('foo')
   .transacting(t)
   .insert({id:"asdfk", username:"barry", email:"[email protected]"})
   .then(function() {
        return knex('foo')
           .where('username','=','bob')
           .update({email:"[email protected]"});
   })
   .then(t.commit)
   .catch(function(e) {
        t.rollback();
        throw e;
   })
})
.then(function() {
 // it worked
})
.catch(function(e) {
 // it failed
});

To understand it better, here's the synchronous version that is being "emulated":

try {
    var t = knex.transaction();
    try {
        knex("foo")
            .transacting(t)
            .insert({id:"asdfk", username:"barry", email:"[email protected]"});
        knex("foo")
            .where('username','=','bob')
            .update({email:"[email protected]"});
        t.commit();
    }
    catch (e) {
        t.rollback();
        // As you can see, if you don't rethrow here
        // the outer catch is never triggered
        throw e;
    }
    // It worked
}
catch (e) {
    //It failed
}
like image 134
Esailija Avatar answered Oct 14 '22 23:10

Esailija