1

Let me preface this by saying my code was working yesterday. I rolled back my commits to the time when it was working.

The only thing that is different is that a migration was ran today to remove some columns from some tables. I can't see how this would affect it

I'm doing google oauth authentication and in my callback url from google I am doing a lot of saves/updates/etc.. My controller calls a single service that does everything. If I query the data while at a breakpoint where the return statement is, I can see the data. There are no exceptions, validation errors, or anything that would lead me to believe anything is wrong. Any ideas?

class MyController {

  def myService

  def callback() {
    myService.update()
    //At this point when I run X.get(1) it is returning null
    redirect uri: "..."
  }
}

@Transactional
class MyService {

  def update() {
    ...
    //If I break at this return statement I can run X.get(1) and it returns
    return someData;
  }
}

Edit: I've found the cause, however I don't understand how this is happening. I'm eventually calling userDetailsService.loadUserByUsername. That method is throwing a NoStackUsernameNotFoundException. I'm catching that exception in my code, however it is causing the transaction to roll back regardless.

James Kleeh
  • 12,094
  • 5
  • 34
  • 61
  • Any exception thrown during a transaction, even if you catch it and deal with it, will cause the transaction to roll back. – rcgeorge23 Jul 02 '15 at 07:52
  • Do you catch the exception inside or outside the transaction? – holmis83 Jul 02 '15 at 11:48
  • @rcgeorge23 Are you sure about that? Can you point me to where in the documentation it says so? I was always under the impression caught exceptions didn't roll back the transaction – James Kleeh Jul 02 '15 at 15:13
  • @holmis83 spring security has their own withTransaction block where it is throwing the exception: https://github.com/grails-plugins/grails-spring-security-core/blob/v2.0-RC4/src/groovy/grails/plugin/springsecurity/userdetails/GormUserDetailsService.groovy. I'm catching that exception exactly where it is being called. – James Kleeh Jul 02 '15 at 15:14

1 Answers1

0

Any exception thrown during a transaction, even if you catch it and deal with it, will cause the transaction to roll back.

To get around this you have a couple of options:

  1. Perform a check before the point at which the exception is raised, and don't execute the offending code under conditions where you know it would throw an exception
  2. Do the transaction handling yourself -

In your service, set

static transactional = false

Then declare your own transaction block:

MyDomain.withTransaction { tx ->
    try {
        userDetailsService.loadUserByUsername(...)
    } catch (NoStackUsernameNotFoundException e) {
        log.warn("Can't load user...")
    } 

    //stuff you try to persist here will 
    //be written to the database successfully 
    //despite the NoStackUsernameNotFoundException
    //being thrown & caught
}
rcgeorge23
  • 3,594
  • 4
  • 29
  • 54
  • The spring security plugin is doing this already. https://github.com/grails-plugins/grails-spring-security-core/blob/v2.0-RC4/src/groovy/grails/plugin/springsecurity/userdetails/GormUserDetailsService.groovy – James Kleeh Jul 02 '15 at 15:10
  • By that I meant they are declaring their own transaction block. They aren't catching the exception there, however I am doing so exactly where it is being called – James Kleeh Jul 02 '15 at 15:17