春季数据-乐观重试机制工作不正常



我的一个服务中有以下代码:

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

有什么想法吗?当从事务函数调用这个方面重试机制时,为什么它没有成功?

从非事务性test()调用@Transactionalexecute()时,不会应用execute()中的@Transactional。这是因为它是从对象的一个方法直接到另一个方法的直接调用,从而绕过事务代理。

有关使用this调用事务函数时代理如何工作以及@Transactional为何不工作的更多详细信息,请参阅此答案。

还可以看看SpringRetryTemplate,它是解决这个问题的基于Spring的解决方案。

关于重试机制,它不适用于使用版本化实体(具有@Version列)的情况,即抛出StaleObjectStateException的情况。

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

解决方案是refresh()实体(加载最新版本),重新应用修改并重试。重复多次相同的修改只会在没有版本的实体的情况下起作用,而且这可能不是你想要的,因为一个线程所做的更改会被另一个线程静默地覆盖。

最新更新