views:

175

answers:

1

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 :)

+2  A: 

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 throw 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.

Gareth Davis
Awesome, thanks!
UltraVi01
glad to be of service
Gareth Davis
Custom exceptions that extend RuntimeException should be OK, right?Also, you can enable transactions in MySQL by setting: dialect = org.hibernate.dialect.MySQLInnoDBDialect in dataSource :)
UltraVi01
Yes any RuntimeException will force a rollback and InnoDB is a good choice for MySQL, only bother with the other table types is you find out you really really need the performance
Gareth Davis