Skip to content


Working with Transactions in Grails

At a certain point when developing an application you will run into a situation that requires you to use transactions. With transactions (in it’s simplest form) you basically control when/whether to commit/rollback a bunch of related sql inserts, updates and/or deletes depending on your business requirements.

I’ve been tinkering around with the different options available in grails to work with transactions and would like to share those different options with who ever might need this info through a very simplistic example just to make things short (keep in mind that behind the scenes it is actually Spring that is managing those transactions)
To begin with, I will explain the scenario we will be working with, and then present the different pieces of source code that I’ve used.

First, this simple application will work with 3 domain classes; Foo, Bar and Baz , all three domains have 1 field called name and a unique constraint on that name. My application has a requirement that
Every time an instance of “Foo” is saved, an instance with the same name should be saved in Bar and Baz
Since each class has a unique constraint on it’s name, saving an instance into Bar and/or Baz could fail when trying to save Foo, in which case, neither Foo nor Bar nor Baz should be saved.

It’s a very weird requirement (and technically you can could achieve those requirements without using transactions), but it serves the purpose of the example. Below is an example flow of someone using the application and what is expected to happen.

Step Action Outcome
1 Add a new Bar with name “Bar1” A new Bar with name “Bar1” is added
2 Add a new Baz with name “Baz1” A new Baz with name “Baz1” is added
3 Add a new Foo with name “Foo1” A new Foo with name “Foo1” is added
A new Bar with name “Foo1” is added
A new Baz with name “Foo1” is added
4 Add a new Foo with name “Bar1” An Error message should be returned and neither Foo, nor Bar, nor Baz should be added since “Bar1” violates a unique constraint on Bar
5 Add a new Foo with name “Baz1” An Error message should be returned and neither Foo, nor Bar, nor Baz should be added since “Baz1” violates a unique constraint on Baz
6 etc…


Implementing Domains and Controllers

Ok, so how do we go about implementing this. Lets start by modeling the domain classes.

Here is an example implementation of the domain Bar, the other classes are exactly the same but with a different class name

class Bar {
    String name
    static constraints = {
        name unique:true
    }
}

Now that I have the domains ready, I will use grails generate-all for each domain class, to generate views and controllers, and then I will do a small change to the Foo controller to add the functionality of adding a Bar and a Baz when saving a Foo instance. (This is will show how things could go wrong)

Add the following to the FooController.groovy under the save action

def save = {
        new Bar(params).save(flush:true)
        new Baz(params).save(flush:true)
        def fooInstance = new Foo(params)
        if (fooInstance.save(flush: true)) {
            flash.message = "${message(code: 'default.created.message', args: [message(code: 'foo.label', default: 'Foo'), fooInstance.id])}"
            redirect(action: "show", id: fooInstance.id)
        }
        else {
            render(view: "create", model: [fooInstance: fooInstance])
        }
    }

What this basically does is save a Bar instance, a Baz instance and a Foo instance when trying to save a Foo instance. We can run the application now and try to follow the same steps outlined above.

You will notice that after completing step 4, a Bar1 instance was added to Foo as well as Baz which is wrong, since a validation constraint was violated on Bar.
I could have checked for validation errors on Bar and Baz to prevent the inconsistent behavior, but the whole purpose is to test out the transactions and how to use them :)


Adding Transactions to the mix

One of many ways to use transactions is using programmatic transactions which involves working with the withTransaction method. I will change the above code to use the withTransaction and see what happens. Change the save action to look something like this.

def save = {
        def fooInstance = new Foo(params)
        Foo.withTransaction{ status ->
            try{
                new Bar(params).save(flush:true, failOnError:true)
                new Baz(params).save(flush:true, failOnError:true)
                fooInstance.save(flush: true, failOnError:true);
            }catch(Exception exp){
                fooInstance.errors.reject(
		    'foo.name.inuse',
                    ["${params.name}"].toArray() as Object[],
                    'Sorry Name [{0}] is already used by either Foor, Bar or Baz!!!')

                status.setRollbackOnly()
            }
        }
        
        if (!fooInstance.hasErrors()) {
            flash.message = "${message(code: 'default.created.message', args: [message(code: 'foo.label', default: 'Foo'), fooInstance.id])}"
            redirect(action: "show", id: fooInstance.id)
        }
        else {
            render(view: "create", model: [fooInstance: fooInstance])
        }
    }

First thing to note, is that the save logic is moved inside the Foo.withTransaction{} block. Everything inside this block is run in a transaction as the name indicates. For simplicity, I have set the failOnError to true when saving, this will throw an exception when we hit the unique constraint, and will allow me to rollback the transaction by setting status.setRollbackOnly(), otherwise, things will carry on in the normal way.
If you try to run the application now, you will notice that it behaves according to the requirements set at the beginning.

Another way to work with transactions, is through grails Services. I will go ahead and create a FooService (grails create-service FooService). The first thing you will notice when you look at the newly created service is the following line of code

static transactional = true

This enables automatic transaction management for the service. Setting this to false, will disable the automatic transaction management. What does automatic transaction management mean? It means that every method in your service is automatically wrapped in a transaction, which will either commit if no exceptions are thrown, or will rollback if an exception is thrown. I will try it out.

I will move the code above to the service, it will look something like this.

class FooService {
    
    static transactional = true

    def saveFoo(params) {
        def foo = new Foo(params)
        new Bar(params).save(flush:true, failOnError:true)
        new Baz(params).save(flush:true, failOnError:true)
        foo.save(flush:true, failOnError:true)
        return foo
    }
}

Since I have failOnError set to true, then an exception will be thrown, which will trigger the rollback of the transaction, otherwise, things will continue normally.

Now In the controller, I will inject the new service and then change the save action as follows

def save = {
        def fooInstance = new Foo(params)
        try{
            fooInstance = fooService.saveFoo(params)
        }catch(RuntimeException e){
            fooInstance.errors.reject(
		'foo.name.inuse',
                ["${params.name}"].toArray() as Object[],
                'Sorry Name [{0}] is already used by either Foor, Bar or Baz!!!')
        }
        
        if (!fooInstance.hasErrors()) {
            flash.message = "${message(code: 'default.created.message', args: [message(code: 'foo.label', default: 'Foo'), fooInstance.id])}"
            redirect(action: "show", id: fooInstance.id)
        }
        else {
            render(view: "create", model: [fooInstance: fooInstance])
        }
    }

This should result in the same exact behavior as the programmatic transaction.

As you can see, it is very easy to work with transactions in grails, although the above example is a little contrived, but hopefully it was helpful to illustrate some of the ways to use transactions in grails. There are other ways to define transactions and control them which are found in the user guide, I haven’t tried them out yet since I didn’t really need to, but fell free to do so.

On another note, if you find yourself usgin failOnError:true a lot, you can always configure it to be the default. As a matter of fact, there is currently a discussion on the grails mailing list whether to change this to be the default behavior or to add a new method to achieve this. You can read all about it over here.

Posted in Programming.

Tagged with .


8 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. John says

    Thanks. It helps clearing some details about transactions.
    God I love Grails!.

  2. http://www.hisenseitalia.it/js/giuseppe-zanotti-sneakers.htm/ says

    We can’t afford to replace top of the line appliances every few years. I also have a dodge grand avan and it’s the biggest POS ever! FTA by implication plays the role of a nicely euphemistic pretext that is used as a new tool in the War on Terror. Generally, accounts receivable refers to the total amount due and is considered in calculating the value of a business or the business’ problems in paying . “This decision was based purely on economics. A restaurant that serves lunch and dinner is on s

  3. Free Zynga Poker Chips says

    This design is steller! You definitely know how to keep a reader amused.
    Between your wit and your videos, I was almost moved to start my own blog (well,
    almost…HaHa!) Great job. I really enjoyed what you had to say, and more than that, how you presented
    it. Too cool!

  4. pinterest says

    Make your images, videos, and infographics
    easy to pin by placing them on the page rather
    than displayed as a background. Google+ is a social networking site
    that has a range of different features that you can use
    to connect with patients and other healthcare
    professionals. There are different ways on getting invited to Pinterest.

  5. adjustable dumbbells says

    future, the researchers want to find out whether a combination of several
    educated in the gastrointestinal tract hormones can further enhance the effect of the gastric band.
    Adiphene is the newest and fastest weight reduction supplement
    in market. Different studies have demonstrated the profits of
    Ginseng Panax Root Extract.

  6. ringing ears treatment says

    future, the researchers want to find out whether a combination of several educated
    in the gastrointestinal tract hormones can further enhance the effect of the
    gastric band. There are various surgical methods to combat obesity.
    With more time now passed, those rates would be even higher as obesity is still on the rise.

  7. ringing in ears cure says

    Don’t let fat cost-free or perhaps gentle meals trick anyone; them usually comprise
    copious amounts connected with one more unhealthy element. Individuals who have underlying medical condition should also consult a physician before taking
    this diet pill. Glucomannan is among the most
    active hunger suppressants in Adiphene, and it works to suppress yearnings and
    help you handle your parts.

  8. treatment for ringing in the ears says

    You wont find Adiphene in your native pharmacy or some huge store
    like Walmart or Walgreens. This means thay everybody who makes use of Adiphene should shed pounds.
    Indeed Adiphene weight reduction pill is the answer for those who always goes
    on food regimen however can’t endure the meals carving hunger and the irritability gave rise by dieting.



Some HTML is OK

or, reply to this post via trackback.