14

In a spring container, with the code below:

public class A {

    @Transactional
    public void m1() {
        ...
        b.m2(); // call in a new transaction
        ...
    }

}

public class B {

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void m2() {
        ...
    }

}

when exactly the transaction created for m2() is committed? once m2() invocation ends, or once m1() invocation ends?

When does @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) commit? answers it for EJB, but it doesn't seem to be the same behavior for JPA.

I debugged it and I can only see the effect of m2() on DB after m1() ends, but that seems odd to me, am I missing something here?

UPDATE:

I was passing the entity I retrieved in m1() to m2() and updating it from there. So, actually merging the entity in m2() solves this and Mik378 answer is correct.

Community
  • 1
  • 1
Ahmad Y. Saleh
  • 3,309
  • 7
  • 32
  • 43

1 Answers1

11

From here:

Whether you're using the Spring Framework or EJB, use of the REQUIRES_NEW transaction attribute can have negative results and lead to corrupt and inconsistent data.
The REQUIRES_NEW transaction attribute always starts a new transaction when the method is started, whether or not an existing transaction is present.

REQUIRES_NEW starts a new transaction even if an existing transaction exist in the context.

So the short answer is: once m2() invocation ends

Mik378
  • 21,881
  • 15
  • 82
  • 180
  • 3
    all this does not say anything about when it -the new transaction- is actually committed, and debugging shows me otherwise. I updated my question plz take a look :) – Ahmad Y. Saleh Mar 12 '14 at 10:39
  • @Ahmad Are you sure that in your test (maybe different than in the sample you provided) `m2()` isn't in the same `class` than `m1()`? Otherwise the proxy (created by the `@Transactional`) would not be set around `m2()` and therefore the commit would append at the end of `m1()`. – Mik378 Mar 12 '14 at 10:46
  • absolutely, two different classes. and I'm sure there are two different transactions for that matter; I tried the case where the first one -created for `m1()`- is rollbacked and i still gets the `m2()` transaction changes committed after – Ahmad Y. Saleh Mar 12 '14 at 10:53
  • @Ahmad What if you try to make a `Thread.sleep(10000)` inside `m1()` just after the call to `m2`? and checking during those 10 seconds that inserted element by `m2()` are commited. – Mik378 Mar 12 '14 at 10:55
  • @Ahmad Indeed..very strange – Mik378 Mar 12 '14 at 10:56
  • @Ahmad Surely that saying "m2() will commit its own transaction" doesn't mean it will do "right now!". There's no spec IMHO that evokes the "when". The proof is that you can rollback m1() without m2() being concerned, meaning the requires_new well works. It can be a kind of optimization, commiting the whole at the end of the top-enclosing transaction. – Mik378 Mar 12 '14 at 11:10
  • 1
    I updated my question, it works as I wanted now and you were right. Thanks :) – Ahmad Y. Saleh Mar 13 '14 at 11:35
  • @AhmadY.Saleh Cool :) something strange in less :) – Mik378 Mar 13 '14 at 12:03
  • What is the solution then? My scenario is same where I want to check m2()'s response and if it's rolled back, then I have to avoid calling m1()'s rest of the code. But m2() is getting committed only after/with m1(). Is there any solution except Thread.sleep(10000)? – Mital Pritmani Apr 07 '17 at 07:53