Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rolling back a transaction in a Grails Service

I have been updating all my services to be transactional by using Grail's ability to rollback when a RuntimeException is thrown in the service. I have, in most cases, doing this:

def domain = new Domain(field: field)
if (!domain.save()) {
   throw new RuntimeException()
}

Anyways, I wanted to verify that this indeed will rollback the transaction... it got me thinking as to whether at this point it's already been committed.. Also, if not, would setting flush:true change that? I am not very familiar with how Spring/Hibernate does all of this :)

like image 481
RyanLynch Avatar asked Jun 05 '10 09:06

RyanLynch


People also ask

What is transactional rollback?

Rolls back an explicit or implicit transaction to the beginning of the transaction, or to a savepoint inside the transaction. You can use ROLLBACK TRANSACTION to erase all data modifications made from the start of the transaction or to a savepoint.

What is transaction rollback exception?

javax.transaction RollbackException exception is thrown when the transaction has been marked for rollback only or the transaction has been rolled back instead of committed. This is a local exception thrown by methods in the UserTransaction , Transaction , and TransactionManager interfaces.

What is @transactional in Grails?

To enable transactions on a service use the Transactional transform: import grails.gorm.transactions.* @Transactional class CountryService { } The result is that all methods are wrapped in a transaction and automatic rollback occurs if a method throws an exception (both Checked or Runtime exceptions) or an Error.


2 Answers

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.

like image 80
Gareth Davis Avatar answered Oct 11 '22 22:10

Gareth Davis


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.

like image 34
Charles Wood Avatar answered Oct 12 '22 00:10

Charles Wood