Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

grails withTransaction - why is it on a domain object?

We need to be able to rollback a complex transaction in a service, without throwing an exception to the caller. My understanding is that the only way to achieve this is to use withTransaction.

The question is:

  1. why do I have to call this on a domain object, such as Books.withTransaction
  2. What if there is no relevant domain object, what is the consequence of picking a random one?

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

someService.groovy

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

The above is flawed - I assume "return ob3" wont return ob3 from the method, as its in a closure. Not sure how to communicate from inside a closure to outside it.

like image 518
John Little Avatar asked Jan 09 '23 11:01

John Little


1 Answers

To your primary question: you can pick a random domain object if you want, it won't do any harm. Or, if you prefer, you can find the current session and open a transaction on that instead:

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

Stylistically I don't have a preference here. Others might.

Not sure how to communicate from inside a closure to outside it.

In general this could be hard; withTransaction could in principle return anything it wants, no matter what its closure argument returns. But it turns out that withTransaction returns the value returned by its closure. Here, watch:

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

By convention, all withFoo methods which take a closure should work this way, precisely so that you can do the thing you're trying to do.

like image 84
David Seiler Avatar answered Feb 16 '23 00:02

David Seiler