views:

337

answers:

1

Hi,

I have a service class that calls other utility classes. These classes themselves sometimes save domain objects and flush them (ex: new User(...).save(flush:true)). I'm calling my service class from a test.

Is my service transactional?

From what I can see in the logs, the Flush Mode is always changing:

impl.SessionImpl setting flush mode to: MANUAL
hibernate.SQL select this_.id as i...
type.StringType binding '1rAdPVixha' to parameter
....
impl.SessionImpl setting flush mode to: AUTO

But my real questions is: If my service method is transactional when called outside of the service (eg: in a test), how can I force the service to rollback all data?


EDIT: I found this:

TransactionAspectSupport.currentTransactionInfo().transactionStatus.setRollbackOnly()

But I still want to know if my service is fully transactional, ie, even if I call domain.save(flush:true) from an utility class within my service method it will run in the same tx context.

Like this:

void testSomething() {
 svc.process(data);
 assert data.exists() ;// true if no rollback happened
}

class MySvc() {
  void process(data) {
    myUtil.process(data);
   }
}

class MyUtil {
  void process(data) { data.save(flush:true)}
}
+2  A: 

The transaction is bound to the thread, and assuming each transactional method has the default 'required' propagation setting, secondary calls will join the active transaction. The initiating call will commit when it finishes, unless something triggers a rollback (a runtime exception or explicit call).

Keep in mind that flush is different from commit. A transactional method will set autocommit to false on the connection, so flushing will push data to the database but it'll be kept in the a temporary transaction queue in case rollback is required. You can flush multiple times, for example if you're doing many inserts and want to reduce application memory usage. When you commit the database will make the temporary changes permanent.

Burt Beckwith
Thanks for the answer. And what happens when I am running my tests with transactional=true *on the test*? AFAIK this attribute on the test makes sure that the data is rolled back at the end of each test method. If this is implemented with transaction propagation I can see this interfering with my service's transaction propagation.
Miguel Ping
A transactional integration test will start and bind a transaction, and transactional services should participate in that. If that's not the case and you can create a repeatable example you should enter a bug in the Grails JIRA.
Burt Beckwith
OK I nailed it down to the tests's "transactional" property. I'll try and come up with a simple test case and submit an issue
Miguel Ping
Just filed a bug report http://jira.codehaus.org/browse/GRAILS-5882
Miguel Ping