views:

33

answers:

1
class ExtHotelApiService extends HotelApiService {

  static scope = "singleton"
  static transactional = true

def save(params) {
  params.hotels.each{ht->
   try{
   transactionalSave(ht)
   } catch(Exception e) {
     /* exceptions handling */
   }
}
}

 @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, rollBackFor=RollBackError.class)
  def transactionalSave(ht) throws RollBackError {
 /* saving hotel and hotel description */
}
}

Note few things:

  1. ExtHotelApiService extends HotelApiService
  2. RollBackError extends RuntimeException
  3. ExtHotelApiService.transactional = true
  4. HotelApiService.transactional = false
  5. We must save hotel and only then save the description
  6. We must roll back transaction (and not persist hotel) if description is not valid (can't be persisted)

All code was wrote according to Declarative Transactions guide but there is one trouble - no roll back happens at all! :(

Transaction successfully commits and hotel is persisted into DB even after RollBackError is thrown!

Where i have make mistake and how to work with declarative transactions in right way ?

+1  A: 

The default behaviour for Spring's declarative transaction management tells the transaction manager to rollback for any unchecked exception, and to ignore any checked exceptions. Checked exceptions can be declared to trigger a rollback, but if the default @Transactional settings are left intact, a checked exception won't have any impact on the current transaction.

The Spring documentation on this is available here, and the relevant sections are 10.5.5, and 10.5.6. Specifically note the following:

Any RuntimeException triggers rollback, and any checked Exception does not.

unsquared
RollBackError is RuntimeException and it still ignores it even if i pass RollBackError.class as rollBackFor parameter. I just can't understand - i have checked exception in this case but even checked exceptions can trigger roll back if they passed as rollBackFor parameter according to the documentation, but... not in my case :(
Olexandr
If it's a RuntimeException, then why have you included it in your method declaration? (Not that this has bearing on the question, but nevertheless curious.)
unsquared
Another point from the grails documention. Warning: dependency injection is the only way that declarative transactions work. You will not get a transactional service if you use the new operator such as new BookService()
unsquared
1. i've included it to method declaration because it was just Throwable at first (you can pass Throwable class as rollBackFor parameter)2. I'm not creating any instances by myself - i'm using dependency injection and singleton pattern
Olexandr
anyway thx :)i'll try to figure out what happened tomorrow
Olexandr
No problem. Sorry I wasn't more help. Best of luck.
unsquared