我的一项服务中包含以下代码:
@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");
}
在从事务函数调用时,为什么这个方面重试机制没有成功的任何想法?
答案 0 :(得分:0)
从非交易@Transactional
致电execute()
test()
时,@Transactional
中的execute()
将不会被应用。这是因为它是从对象的一个方法直接调用到另一个方法,它绕过了事务代理。
有关代理如何工作以及使用@Transactional
调用事务函数时this
无效的原因的详细信息,请参阅此answer。
另请参阅Spring RetryTemplate,这是针对此问题的基于Spring的解决方案。
关于重试机制,对于使用版本化实体(具有@Version
列)的情况,它将不起作用,这是在抛出StaleObjectStateException
的情况下。
原因是有另一个线程更新数据库上的实体,递增版本列。
解决方案是refresh()
实体(加载最新版本),重新应用修改并重试。重试多次相同的修改只适用于非版本化实体,并且它可能不是您想要的,因为一个线程所做的更改会被另一个线程静默覆盖。