Grails withTransaction - why is it on a domain object?

We need to be able to rollback a complex transaction in the service without throwing an exception for the caller. I understand that the only way to achieve this is to use with Transaction.

The question arises:

  • Why do I need to call this on a domain object like Books.withTransaction
  • What if there is no corresponding domain object, which is a consequence of choosing a random one?

Below is more or less what I am trying to do. The use case is to withdraw from an account and put it on a credit card. If the transfer fails, we want to cancel the transaction, but not the payment record log, which should be recorded in a separate transaction (using RequiresNew). In any case, the service method should return a complex object, not an exception.


Class SomeService {
    SomeComplexObject someMethod() {
        SomeDomainObject.withTransaction{ status ->
            DomainObject ob1 = new
            LogDomainObject ob2 = insertAndCommitLogInNewTransaction()
            SomeComplexObject ob3 = someAction()
            if (!ob3.worked) {
                 status.setRollbackOnly() // only rollback ob1, not ob2!
            return ob3


The above is flawed - I am assuming "return ob3" will not return ob3 from the method as it does in the closure. Not sure how to communicate from within the closure to go beyond it.


source to share

1 answer

Into your main question, you can choose a random domain object if you like, it won't hurt. Or, if you like, you can find the current session and open a transaction instead:

grailsApplication.sessionFactory.currentSession.withTransaction { /* Do the things */ }


Stylistically, I have no preference here. Others can.

Not sure how to communicate from inside the closure to the outside.

In general, this can be difficult; withTransaction

can basically return whatever it wants, no matter what its closure argument returns. But it turns out that it withTransaction

returns the value returned by its closure. See here:

groovy> println(MyDomainObject.withTransaction { 2 + 2 })


By convention, all methods withFoo

that accept a closure should work in such a way that you can do what you are trying to do.



All Articles