1

I have two methods annotated with transactional (they are on the same level - have the same parent transaction, as sketched below):

@javax.transaction.Transactional
persist() {
    persistEntities1()
    persistEntities2()
}

@javax.transaction.Transactional(value = Transactional.TxType.REQUIRES_NEW)
persistEntities1() {}

@javax.transaction.Transactional(value = Transactional.TxType.REQUIRES_NEW)
persistEntities2() {}

In persistEntities1 everything is OK, there is a merge call on EntityManager instance. In persistEntities2 there is an uncaught exception.

Problem: entities that should get persisted in persistEntities1 do not get persisted.

Why is this happening? I thought that REQUIRES_NEW ensures that transaction gets committed at the end of method.

I am using Wildfly 8.2.

Uros K
  • 3,274
  • 4
  • 31
  • 45
  • Are you commiting the transaction after the end of the first method? – Dalton Jan 20 '15 at 18:06
  • No, not explicitly. I thought jboss manages transactions for me. – Uros K Jan 20 '15 at 18:07
  • according to this link: http://docs.oracle.com/javaee/7/api/javax/transaction/Transactional.TxType.html, REQUIRES_NEW will create new transactions and will interrupt already going ones. So there's a possibility that your 2nd method is suspending the 1st transaction before it can commit. Have you tried REQUIRED? – Dalton Jan 20 '15 at 18:18
  • No, this kind of behaviour is not allowed. It says in docs: "If called inside a transaction context, the current transaction context must be suspended, a new JTA transaction will begin, the managed bean method execution must then continue inside this transaction context, the transaction must be completed, and the previously suspended transaction must be resumed." – Uros K Jan 20 '15 at 18:21
  • Exactly. That means that when you call the 2nd method, anything that is happening at the 1st transaction will be suspended and resumed after the 2nd transaction ends. – Dalton Jan 20 '15 at 18:23
  • Ok - but why didn't a transaction within persistEntities1() {} complete at the end of persistEntities1 method? – Uros K Jan 20 '15 at 18:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/69241/discussion-between-genesiss-and-dalton). – Uros K Jan 20 '15 at 18:27

2 Answers2

1

The solution was to move both methods persistEntities1 and persistEntities2to separate bean. Now the behavior is as expected.

It seems that this specific jpa implementation ignores child transaction annotations if child methods live in same bean as parent method.

Uros K
  • 3,274
  • 4
  • 31
  • 45
  • 1
    Could it be that this annotation only works on public methods? (like Spring) From your example it looks like you have friendly access on the method annotated with REQUIRES_NEW. – Chris Ritchie Feb 26 '16 at 10:02
0

The reason that would happen is because a RuntimeException was thrown within the execution of persistEntities1().

See why does transaction roll back on RuntimeException but not SQLException.

It doesn't seem to matter whether the exception has been caught and handled or not, the transaction context still gets set to "rollback only".

Community
  • 1
  • 1
gknicker
  • 5,509
  • 2
  • 25
  • 41
  • They are both at the same level (they are called one after another) - they have the same parent transaction. – Uros K Jan 20 '15 at 18:15
  • Are they being called from a transaction-managed scope? In other words, is there another transaction enveloping both calls? – gknicker Jan 20 '15 at 18:17
  • But I have REQUIRED_NEW. The docs say that if REQUIRED_NEW is used, current transaction context gets suspended, a new JTA transaction begins and execution continues inside this context, then the transaction is completed and previously suspended transaction is resumed: http://docs.oracle.com/javaee/7/api/javax/transaction/Transactional.TxType.html#REQUIRES_NEW – Uros K Jan 20 '15 at 18:25
  • What you say is true. Here are some other answers which seem to support your understanding: http://stackoverflow.com/questions/10817838/ejb-3-0-nested-transaction-requires-new and http://stackoverflow.com/questions/12552198/why-nested-transactions-are-not-supported-in-jta. – gknicker Jan 20 '15 at 18:40
  • I've updated my answer based on the new information you've provided. See if that helps. – gknicker Jan 20 '15 at 18:46
  • Actually - I am more confused now :) 1. persistEntities1() has no errors 2. persistEntities2() has an error --> I wrapped content of persistEntities2 in try-catch and now it works. It seems that parent transaction gets rolled back if there is an error in one of the children - even if children methods are annotated with REQUIRES_NEW attribute. And also - it seems that if exception gets caught, transaction doesn't get set to "rollback only". – Uros K Jan 20 '15 at 19:06
  • I understand an exception was *apparently* not thrown from `persistEntities1()`, but I'm pretty sure you will find there was in fact an exception thrown within its context, which was caught and handled. – gknicker Jan 20 '15 at 19:13
  • If there is no exception in persistEntities2(), data from persistEntities1() gets persisted, so I think (in my framework/app server stack) that there is no exception in persistEntities1. – Uros K Jan 21 '15 at 10:27
  • I see. Thanks for clarifying, It seems Wildfly does not standardly implement JavaEE transaction behavior. Your parent transaction is rolling back when any of the child transactions fails. Have you looked for a related configuration setting in Wildfly? – gknicker Jan 21 '15 at 16:03