Partial Rollback while using narayana-jta transaction manager

198 views
Skip to first unread message

DEEPESH SHARMA

unread,
Jun 16, 2021, 4:44:50 AM6/16/21
to narayana-users
Hi All,

I am trying to replicate a simple scenario of Transaction Rollback using narayana-jta transaction manager. Here's my problem -

I have 2 entities named 'Owner' and 'Vets' respectively. I try to save them one after the other in the same transaction. (Refer below code)

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testTransaction(Owner owner) {
Vet vet = new Vet();
vet.setFirstName(owner.getFirstName());
vet.setLastName(owner.getLastName());
vetRepository.save(vet);
ownerRepository.save(owner);
}

Now, when an exception if thrown while saving the Owner (deliberate ConstraintViolation done), the 'Owner' object save is obviously not processed, but the 'Vets' save is committed, and then isn't rolled back, which should have been done in the Ideal case.

Is this some known issue? I couldn't find anything on the community forum so far.
Kindly suggest.

Application LOGS (For Reference)


DEBUG JtaTransactionManager - Initiating transaction commitDEBUG JtaTransactionManager - Initiating transaction commitDEBUG AbstractFlushingEventListener - Processing flush-time cascadesDEBUG AbstractFlushingEventListener - Dirty checking collectionsDEBUG AbstractFlushingEventListener - Flushed: 2 insertions, 0 updates, 0 deletions to 2 objectsDEBUG AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collectionsDEBUG EntityPrinter - Listing entities:DEBUG EntityPrinter - org.springframework.samples.petclinic.model.Owner{pets=null, firstName=ThumsDown1, lastName=jcbj1, address=ncbwj1, city=cbw1, telephone=98867857678981, id=5000047}DEBUG EntityPrinter - org.springframework.samples.petclinic.model.Vet{firstName=ThumsDown1, lastName=jcbj1, specialties=null, id=5000046}DEBUG SQL - insert into vets (first_name, last_name, id) values (?, ?, ?)Hibernate: insert into vets (first_name, last_name, id) values (?, ?, ?)DEBUG JdbcCoordinatorImpl - Skipping aggressive release due to manual disablingDEBUG PlatformResourceBundleLocator - ValidationMessages not found.DEBUG PlatformResourceBundleLocator - ContributorValidationMessages not found.DEBUG PlatformResourceBundleLocator - org.hibernate.validator.ValidationMessages found.DEBUG LogicalConnectionManagedImpl - Initiating JDBC connection release from afterStatementDEBUG TransactionImpl - TransactionImpl created on closed Session/EntityManagerDEBUG TransactionImpl - On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == falseWARN  arjuna - ARJUNA012125: TwoPhaseCoordinator.beforeCompletion - failed for SynchronizationImple< 0:ffffc0a86e01:e5b3:60c05e5d:3, org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization@64639fee >javax.validation.ConstraintViolationException: Validation failed for classes [org.springframework.samples.petclinic.model.Owner] during persist time for groups [javax.validation.groups.Default, ]List of constraint violations:[ ConstraintViolationImpl{interpolatedMessage='numeric value out of bounds (<10 digits>.<0 digits> expected)', propertyPath=telephone, rootBeanClass=class org.springframework.samples.petclinic.model.Owner, messageTemplate='

{javax.validation.constraints.Digits.message}

'}] at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140) at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80) at org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:227) at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:100)

Ondra Chaloupka

unread,
Jun 16, 2021, 5:29:40 AM6/16/21
to narayana-users
Hi Deepesh,

thanks for you question. From the discussion started at the https://issues.redhat.com/browse/JBTM-3495 I can see that the both entities are part of the same global transaction.
The failure (https://docs.oracle.com/javaee/7/api/javax/validation/ConstraintViolationException.html) happens in the Synchronization.beforeCompletion hook (https://docs.oracle.com/javaee/7/api/javax/transaction/Synchronization.html) which is how the hibernate integrates and which should cause the transaction to be rolled-back.

First, please verify that the persistence unit is configured as JTA (ie. capable to work in the global transaction). In Java SE the default could be the  RESOURCE_LOCAL which could be the cause. For deeper understanding what's the difference then I would recommend e.g. this ebook - https://www.infoq.com/minibooks/JTDS/ - to get insight on local and global transactions.
If you confirm that all is managed withing global transaction and the persistence unit is setup correctly then can you provide TRACE log information from the Narayana processing? It's the category 'com.arjuna' that should be defined with TRACE level and then provide us with the detailed log of the transaction processing.

Thanks
Ondra

DEEPESH SHARMA

unread,
Jun 28, 2021, 9:10:09 AM6/28/21
to narayana-users
Hi All

Please refer the below source code from narayana-jta jar (TwoPhaseCoordinator.class)

I have debugged the code, and got to a conclusion that from here the call is directed to Hibernate for marking the transaction as RollbackOnly(). But post that no call actually lands up at rollback() method in Base Transaction, which should actually initiate the process of Rolling back the first step (The step executed before exception occurs). 

Can anyone explain, how and when (in an ideal scenario), the rollback() would be called after the transaction  is marked as rollbackOnly()?


protected boolean beforeCompletion() {
boolean problem = false;
synchronized(this._syncLock) {
if (!this._beforeCalled) {
this._beforeCalled = true;
if (this._synchs != null) {
if (TxControl.asyncBeforeSynch && this._synchs.size() > 1) {
problem = !this.asyncBeforeCompletion();
} else {
int lastIndexProcessed = -1;
SynchronizationRecord[] copiedSynchs = (SynchronizationRecord[])((SynchronizationRecord[])this._synchs.toArray(new SynchronizationRecord[0]));

while(lastIndexProcessed < this._synchs.size() - 1 && !problem) {
if (copiedSynchs.length != this._synchs.size()) {
copiedSynchs = (SynchronizationRecord[])((SynchronizationRecord[])this._synchs.toArray(new SynchronizationRecord[0]));
}

++lastIndexProcessed;
this._currentRecord = copiedSynchs[lastIndexProcessed];

try {
problem = !this._currentRecord.beforeCompletion();
} catch (Exception var7) {
tsLogger.i18NLogger.warn_coordinator_TwoPhaseCoordinator_2(this._currentRecord.toString(), var7);
if (this._deferredThrowable == null) {
this._deferredThrowable = var7;
}

problem = true;
} catch (Error var8) {
tsLogger.i18NLogger.warn_coordinator_TwoPhaseCoordinator_2(this._currentRecord.toString(), var8);
if (this._deferredThrowable == null) {
this._deferredThrowable = var8;
}

problem = true;
}
}
}
}
}

if (problem && !this.preventCommit()) {
tsLogger.i18NLogger.warn_coordinator_TwoPhaseCoordinator_1();
}
}

return !problem;
}


--
You received this message because you are subscribed to a topic in the Google Groups "narayana-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/narayana-users/D16JTYmLiHM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to narayana-user...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/narayana-users/da8402f6-3185-4184-b5b4-4d34fce1dd59n%40googlegroups.com.

Michael Musgrove

unread,
Jun 28, 2021, 10:15:03 AM6/28/21
to narayana-users
The JTA spec [1] only requires us to call beforeCompletion synchronisations if the transaction is going to commit and setRollbackOnly implies that the transaction is going to rollback.

But the narayana transaction manager allows this behaviour to be configurable (by default we don't call it if the transaction is going to rollback). If you wish to override this behaviour then set the property https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/CoordinatorEnvironmentBean.java#L620 to true.

[1] "The Synchronization.beforeCompletion method is called prior to the
start of the two-phase transaction commit process. This call is executed with
the transaction context of the transaction that is being committed."

Michael Musgrove

unread,
Jun 28, 2021, 10:55:24 AM6/28/21
to narayana-users
If one entity commits and the other rolls back the suspicion would be that you aren't using JTA. Googling persistence unit I see that it accepts a JTA attribute (<persistence-unit name="xyz" transaction-type="JTA">), what do your persistence units look like. Is there a simple reproducer that one of us can run in a debugger (or inspect) to determine why both resources (vetRepository and ownerRepository) aren't included in a JTA transaction.

Michael Musgrove

unread,
Jun 28, 2021, 11:19:46 AM6/28/21
to narayana-users
I have just downloaded "JSR 317: Java TM Persistence API, Version 2.0" and the sections you should look at are "7.5.1 JTA EntityManagers" and section "8.2.1.2 transaction-type".
It has been a while since I did anything with JPA but, if you are still sure that you are using a JTA entity manager after looking at those two sections then if you can provide a reproducer I will take a look.

Ondra Chaloupka

unread,
Jun 28, 2021, 12:18:22 PM6/28/21
to narayana-users
Hi Deepesh,

as Mike mentioned and as I tried to explain in my first post you really need to check what participants were enlisted into transaction. The best would be if you can share the reproducer or at least to share the application log with category 'com.arjuna' set to level TRACE.

To your code. Yes, the `beforeCompletion` is the sychronization callback which was registered by Hibernate. Then the Hibernate (probably) marks the transaction with flag setRollbackOnly. That call does not invokde the Transaction.rollback() call. The setRollbackOnly only marks the flag. When transaction is to be finished (see https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/BasicAction.java#L1485) then Narayana calls either rollback or commit based on the flag (and potentially depending on other context).

Ondra

DEEPESH SHARMA

unread,
Jun 28, 2021, 12:34:50 PM6/28/21
to Ondra Chaloupka, narayana-users
Hi Ondra,

I will post the Logs and reproducer soon.

Just an info, in my case first of all the Commit call is made and then during the Commit the Constraint Violation Exception is thrown, after which the exception handler marks the transaction as Rollback Only. 

Post this marking there is no actual Rollback() call made.

Let me know, if this info clicks up anything.

Regards,
Deepesh


Mark Little

unread,
Jun 29, 2021, 4:43:51 AM6/29/21
to DEEPESH SHARMA, Ondra Chaloupka, narayana-users
Have you tried to duplicate this behaviour in one of the tests in the ArjunaJTA repo? There are a few using Synchronizations and I would suggest you try there as they’ll remove one variable initially, JPA.

Mark.


You received this message because you are subscribed to the Google Groups "narayana-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to narayana-user...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/narayana-users/CAAaE1w9PFB92LreCH1VwFQdq%2BZDupB6%3DDsE8w9Oz2-E3tcXnoA%40mail.gmail.com.

---
Mark Little
mli...@redhat.com

JBoss, by Red Hat
Registered Address: Red Hat Ltd, 6700 Cork Airport Business Park, Kinsale Road, Co. Cork.
Registered in the Companies Registration Office, Parnell House, 14 Parnell Square, Dublin 1, Ireland, No.304873





Michael Musgrove

unread,
Jun 29, 2021, 5:45:34 AM6/29/21
to DEEPESH SHARMA, Ondra Chaloupka, narayana-users
On Mon, Jun 28, 2021 at 5:35 PM DEEPESH SHARMA <f201...@alumni.bits-pilani.ac.in> wrote:
Hi Ondra,

I will post the Logs and reproducer soon.

Just an info, in my case first of all the Commit call is made and then during the Commit the Constraint Violation Exception is thrown, after which the exception handler marks the transaction as Rollback Only. 

Post this marking there is no actual Rollback() call made.

I suspect that you are not using JTA. Did you check the transaction-type attribute of your persistence unit (I mentioned the details in my previous response)?

You received this message because you are subscribed to the Google Groups "narayana-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to narayana-user...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/narayana-users/CAAaE1w9PFB92LreCH1VwFQdq%2BZDupB6%3DDsE8w9Oz2-E3tcXnoA%40mail.gmail.com.


--
Michael Musgrove

JBoss, by Red Hat
Registered Address: Red Hat Ltd, 6700 Cork Airport Business Park, Kinsale Road, Co. Cork.
Registered in the Companies Registration Office, Parnell House, 14 Parnell Square, Dublin 1, Ireland, No.304873
Directors:Michael Cunningham (USA), Vicky Wiseman (USA), Michael O'Neill, Keith Phelan, Matt Parson (USA)


Reply all
Reply to author
Forward
0 new messages