春季乐观锁定:如何在提交成功之前重试事务方法
我将Spring 2.5和Hibernate JPA实现与Java和“容器”托管事务结合使用。
我有一个“用户提交后”方法,该方法在后台更新数据,并且无论是否异常都需要提交,因为它永远不会显示给客户端。换句话说,需要让乐观锁定到悲观。(如果方法执行需要更长的时间并且有人在其他事务中更改了数据,则可能会发生这种情况)ConcurrencyFailureException
StaleObjectStateException
我读了很多关于幂等的东西,如果异常,请重试,以搜索DEFAULT_MAX_RETRIES或6.2.7。示例或第 14.5 章。重试。我也在这里和这里发现了堆栈溢出。
我试过这个:
public aspect RetryOnConcurrencyExceptionAspect {
private static final int DEFAULT_MAX_RETRIES = 20;
private int maxRetries = DEFAULT_MAX_RETRIES;
Object around(): execution( * * (..) ) && @annotation(RetryOnConcurrencyException) && @annotation(Transactional) {
int numAttempts = 0;
RuntimeException failureException = null;
do {
numAttempts++;
try {
return proceed();
}
catch( OptimisticLockingFailureException ex ) {
failureException = ex;
}
catch(ConcurrencyFailureException ex) {
failureException = ex;
}
catch( StaleObjectStateException ex) {
failureException = ex;
}
} while( numAttempts <= this.maxRetries );
throw failureException;
}
}
RetryOnConcurrencyException
是我的注释,用于标记在发生异常时需要重试的方法。不起作用...我也尝试了几种方法,如,SELECT ... FOR UPDATE
EntityManager.lock(...)
避免陈旧数据,脏读等的最佳方法是什么,这种策略与Spring?重试、已同步、JPA 锁定、隔离,选择...更新?我无法让它工作,我对任何帮助都感到非常高兴。
以下是我喜欢做的一些伪代码:
void doSomething(itemId) {
select something into A;
select anotherthing into B;
// XXX
item = getItemFormDB( itemId ); // takes long for one user and for other concurrent user it could take less time
item.setA(A);
item.setB(B);
// YYYY
update item;
}
在 // XXX 和 // YYY 之间,另一个会话可以修改该项目,然后抛出 StaleObjectStateException。