I'm using spring data jpa with @EnableJpaRepositories
and spring retry with @EnableRetry
.
I want to retry a transactional method that calls another transactional method that acquires an Oracle DBMS_LOCK
using a wrapper stored proc: MY_PROC_THAT_CALLS_ORACLE_DBMS_LOCK
.
The lock acquired is set up to be released upon transaction commit and that is what I want.
But despite successfully acquiring the lock on, say, the second attempt, my transaction is getting marked as rollback_only
and is failing.
I suspect the @Transactional
annotation on my acquireDbmsLock
method in my Repository is seeing the SQLException
and setting the transaction to roll back only.
From my understanding of the transaction propogation semantics, I think I don't want @Transactional(propogation = Propogation.REQUIRES_NEW)
on the acquireDbmsLock
interface method. Looks like Hibernate doesn't support Propogation.NESTED
.
So, what is a good solution for this problem?
I'm resisting setting noRollbackFor = SQLException.class
.
Here's my code:
@Retriable(SQLException.class)
@Transactional
public MyThing myService(String thingId) {
MyThing myThing = myRepository.findMyThing(thingId);
if(myThing == null) {
myLockRepository.acquireDbmsLock(thingId);
myRepository.createMyThing(thingId);
} else {
return myThing;
}
}
public interface MyLockRepository extends Repository<XXX, YY> {
@Procedure(procedureName = "MY_PROC_THAT_CALLS_ORACLE_DBMS_LOCK")
void acquireDbmsLock(String lockName);
}
I've tried overriding the default retry configuration as shown below as well (after removing the @EnableRetry
annotation):
@Bean
RetryConfiguration retryConfiguration() {
// Need retries to happen before transaction is set to rollback only: https://stackoverflow.com/a/53654301/499635
return new RetryConfiguration() {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
};
}