简体   繁体   中英

Spring data - Optimistic retry mechanism not working properly

I'm having the following code inside one of my services:

@Override
@Transactional
@RetryConcurrentOperation(exception = Exception.class, retries = 12)
public void test() {

Player player = this.playerRepository.findPlayerById(1L);
player.setFirstName("SomeName");
}

the retry mechanism i'm using is the one that was described here: http://josiahgore.blogspot.co.il/2011/02/using-spring-aop-to-retry-failed.html

problem is when i get an optimistic retry (2nd retry) i get an exception:

Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [xxx]

Interesting this is that the mechanism works when i'm removing the transactional annotation and within the non transactional function i'm calling a different transactional method:

// THIS WORKS: 
@Override
@RetryConcurrentOperation(exception = Exception.class, retries = 12)
public void test() {
 execute();

}   

@Override
@Transactional
public void execute() {
Player player = this.playerRepository.findPlayerById(1L);
player.setFirstName("SomeName");
}

Any ideas why this aspect retry mechanism is not succeeding when it's being invoked from a transactional function?

When calling @Transactional execute() from non transactional test() , the @Transactional in execute() will NOT be applied. This is because it's a direct call from one method of the object directly to the other, which bypasses the transactional proxy.

See this answer for more details on how proxies work and why @Transactional does not work when calling the transactional function using this .

Have a look also at the Spring RetryTemplate , which is a spring-based solution for this problem.

Concerning the retry mechanism, it won't work for cases when a versioned entity (with a @Version column) is being used, which is the case given that StaleObjectStateException is being thrown.

The reason is that there was another thread updating the entity on the database, incrementing the version column.

The solution is to refresh() the entity (loading the latest version), reapply the modifications and try again. Retrying several times the same modification will only work in case of non versioned entities, and it's probably not what you want because the changes made by one thread are silently overwritten by another thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM