4

Back in the day, it was common to manage database transactions in Java by writing code that did it. Something like this:

Transaction tx = session.startTransaction();
...
try {
   tx.commit();
} catch (SomeException e){
   tx.rollback();
}

at the beginning and end of every method. This had some obvious problems - it's redundant, hides the intent of what's happening, etc. So, along came annotation-driven transactions:

@Transaction
public SomeResultObj getResult(...){

    ...
}

Is there any support for declarative transaction management in node.js?

  • didn't know that was ever common... I've always written code to have a central place to execute JDBC code from and handle transactions, it's just a good idea... – jwenting Jun 11 '14 at 9:29
  • Most people have avoided writing their own database transaction API because they dislike re-inventing the wheel, combined with the fact that most of the available options are safer, and easier to use than rolling your own. – Ampt Oct 20 '14 at 17:59
  • Agreed with not rolling one's own database transaction API! I would certainly like to know if there are any existing declarative database transaction APIs in Node.js. – James Kingsbery Oct 20 '14 at 18:40
2

In case you're using Express + Sequelize, you can do this by using a module called continuation-local-storage (henceforth cls, for brevity).

Show me the code

// When initializing your Sequelize instance
var Sequelize = require( "sequelize" );
Sequelize.cls = require( "continuation-local-storage" ).createNamespace( "db" );

module.exports = new Sequelize(...);

Then, create some middleware to initialize your transaction in every request (in case no one has come up with one yet):

var sequelize = require(...);
app.use(function ( req, res, next ) {
  sequelize.transaction(function () {
    // Do something else, but be sure to invoke next middleware
    next();    
  });
});

What's going on here?

  1. A cls namespace is declared for Sequelize to use. Must be set on the constructor;
  2. A transaction is initialized in an Express middleware;
  3. Every subsequent sequelize query will use the request transaction by default (you can override this behavior, obviously).

How this works?

This works because cls assigns a new storage for each new async chain (the request in this example), and they are passed down consistently and transparently.
It's some kind of magic that happens inside Node :)

Tips

It's very likely that you'll need to use some monkeypatch to take that approach. Depends on your Promises implementation.

Further info

Check the Sequelize documentation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.