2014-02-09 18 views
2

我在里面我的服务之一下面的代码:春数据 - 乐观重试机制不能正常工作

@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] 

有趣,这是该机制WOR KS当我删除事务注释和非交易功能中我打电话的不同事务方法:

// 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

到底有没有@Transactional在这些情况下工作?我认为那里有两个问题,一个是事务处理对于可重入调用不起作用,另一个对于版本化实体不起作用,这是你在哪里寻找的答案,还是其他的东西? –

+0

尝试此解决方案:https://stackoverflow.com/a/45543257/516167 – MariuszS

回答

0

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

有关代理如何工作以及为什么@Transactional在使用this调用交易功能时不起作用的更多详细信息,请参阅此answer

还可以看看Spring RetryTemplate,这是一个基于弹簧的解决方案。

关于重试机制,对于使用版本化实体(使用@Version列)的情况,对于引发StaleObjectStateException的情况将不适用。

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

解决的办法是到refresh()该实体(加载最新版本),重新应用修改并重试。重试几次相同的修改只适用于非版本化实体的情况,它可能不是您想要的,因为一个线程所做的更改将被另一个线程悄悄覆盖。

+0

似乎RetryTemplat不是通用的。每当我想重试时,我需要实现一个特殊的回调函数。 – lior

+0

他回调允许应用一些恢复逻辑(例如写入另一个表,记录日志表中的异常等)。并且在没有@Transactional的情况下在数据库中触发更新/插入的位置? –

+0

我已经添加了为什么我认为@Transactional没有应用,这是绕过代理的一个可重复调用。此外,对于版本化实体(此处为案例),博客文章中的策略无效,请参阅上面的更新回答 –