Transaction manager to not retry inner transactions (#1974)

This commit is contained in:
Pavlo Tkach 2023-04-05 16:46:36 -04:00 committed by GitHub
parent 33b43c05e7
commit 8d7088552f
2 changed files with 30 additions and 0 deletions

View file

@ -154,6 +154,10 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
@Override @Override
public <T> T transact(Supplier<T> work) { public <T> T transact(Supplier<T> work) {
// This prevents inner transaction from retrying, thus avoiding a cascade retry effect.
if (inTransaction()) {
return transactNoRetry(work);
}
return retrier.callWithRetry(() -> transactNoRetry(work), JpaRetries::isFailedTxnRetriable); return retrier.callWithRetry(() -> transactNoRetry(work), JpaRetries::isFailedTxnRetriable);
} }

View file

@ -580,6 +580,32 @@ class JpaTransactionManagerImplTest {
.isFalse()); .isFalse());
} }
@Test
void innerTransactions_noRetry() {
JpaTransactionManager spyJpaTm = spy(tm());
doThrow(OptimisticLockException.class).when(spyJpaTm).delete(any(VKey.class));
spyJpaTm.transact(() -> spyJpaTm.insert(theEntity));
Supplier<Runnable> supplier =
() -> {
Runnable work = () -> spyJpaTm.delete(theEntityKey);
work.run();
return null;
};
assertThrows(
OptimisticLockException.class,
() ->
spyJpaTm.transact(
() -> {
spyJpaTm.exists(theEntity);
spyJpaTm.transact(supplier);
}));
verify(spyJpaTm, times(3)).exists(theEntity);
verify(spyJpaTm, times(3)).delete(theEntityKey);
}
private void insertPerson(int age) { private void insertPerson(int age) {
tm().getEntityManager() tm().getEntityManager()
.createNativeQuery(String.format("INSERT INTO Person (age) VALUES (%d)", age)) .createNativeQuery(String.format("INSERT INTO Person (age) VALUES (%d)", age))