Rolling back a transaction in a Grails Service Rolling back a transaction in a Grails Service spring spring

Rolling back a transaction in a Grails Service


Yep that'll do it.

Transactions in Grails are by default handled at a Service method level. If the method returns normally then the transaction will be committed, if a RuntimeException is thrown the transaction will be rolled back.

Note this means even if you use flush:true on while saving an object in the server method the db changes will still be rolled back if you throw a RuntimeException.

For example:

class MyService { def fiddle(id,id2){   def domain = Domain.findById(id)   domain.stuff = "A change"   domain.save( flush:true ) // will cause hibernate to perform the update statements   def otherDomain = OtherDomain.findById(id2)         otherDomain.name = "Fiddled"   if( !otherDomain.save( flush:true )){ // will also write to the db     // the transaction will be roled back      throw new RuntimeException("Panic what the hell happened")   }                                                            }}

What I'm not 100% clear on with Grails is what happens if a checked exception is thrown in straight java/spring world the default behaviour is for the transaction inceptor to commit the transaction, althrough this can be overriden in the config.

Note: there is a caveat, and that is that your db has to support transactions on the tables you are updating. Yes, this is poke at MySQL :)

This also applies to the Domain.withTransaction method.


Just wanted to add additional comments to the accepted answer, and this was too long to fit into a comment.

What I'm not 100% clear on with Grails is what happens if a checked exception is thrown

By default, the exception must NOT be checked, or the transaction won't be rolled back. Apparently that's a Spring thing.

If you really want to check the exceptions on a method, you can explicitly mark the service method as @Transactional and use the rollbackFor argument to list which exceptions should still cause a rollback. (Note that I haven't actually tested this.)

Be aware, though, that marking any one method in a service with @Transactional disables the automatic wrapping of its other methods with a transaction. So, if you do it for one, you have to do it for all of them. Be sure you really need to declare those checked exceptions ;)

You can read more about this at http://docs.grails.org/latest/guide/services.html.