Spring数据 - 乐观重试机制无法正常工作

时间:2014-02-09 09:33:18

标签: java spring aop aspectj optimistic-locking

我的一项服务中包含以下代码:

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

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

我正在使用的重试机制是这里描述的: http://josiahgore.blogspot.co.il/2011/02/using-spring-aop-to-retry-failed.html

问题是当我得到乐观的重试(第二次重试)时,我得到一个例外:

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

有趣的是,当我删除事务性注释时,该机制有效,并且在非事务性函数中,我调用的是另一种事务方法:

// 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");
}

在从事务函数调用时,为什么这个方面重试机制没有成功的任何想法?

1 个答案:

答案 0 :(得分:0)

从非交易@Transactional致电execute() test()时,@Transactional中的execute()将不会被应用。这是因为它是从对象的一个​​方法直接调用到另一个方法,它绕过了事务代理。

有关代理如何工作以及使用@Transactional调用事务函数时this无效的原因的详细信息,请参阅此answer

另请参阅Spring RetryTemplate,这是针对此问题的基于Spring的解决方案。

关于重试机制,对于使用版本化实体(具有@Version列)的情况,它将不起作用,这是在抛出StaleObjectStateException的情况下。

原因是有另一个线程更新数据库上的实体,递增版本列。

解决方案是refresh()实体(加载最新版本),重新应用修改并重试。重试多次相同的修改只适用于非版本化实体,并且它可能不是您想要的,因为一个线程所做的更改会被另一个线程静默覆盖。