我使用Spring 2.5和Hibernate JPA实现以及Java和“容器”管理的事务。我有一个“用户提交后”更新数据的方法,并且需要提交该方法,无论ConcurrencyFailureException或StaleObjectStateException异常是否发生,因为它永远不会显示给客户端。换句话说,需要将乐观锁转化为悲观锁。(如果方法执行时间稍长,而其他事务中的某些人更改了数据,则可能会发生这种情况)
我阅读了很多关于幂等性,重试异常的文章,如在DEFAULT_MAX_RETRIES搜索或6.2.7. 示例或第14.5章 重试。我还在stackoverflow上找到了这里和这里。
我尝试过以下代码:
我阅读了很多关于幂等性,重试异常的文章,如在DEFAULT_MAX_RETRIES搜索或6.2.7. 示例或第14.5章 重试。我还在stackoverflow上找到了这里和这里。
我尝试过以下代码:
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锁?隔离级别?使用 select ... for update
?我无法让它生效,非常感谢任何帮助。
下面是我想做的一些伪代码:
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 异常。