【发布时间】:2011-03-09 19:27:39
【问题描述】:
我将 Spring 2.5 和 Hibernate JPA 实现与 Java 和“容器”托管事务一起使用。
我有一个“用户提交后”方法,它在后台更新数据,无论ConcurrencyFailureException 或StaleObjectStateException 异常,都需要提交,因为它永远不会显示给客户端。换句话说,需要把乐观锁变成悲观。 (如果方法执行需要更长的时间并且有人在其他事务中更改了数据,则可能会发生)
我读了很多关于幂等的东西,如果 search for DEFAULT_MAX_RETRIES 或 6.2.7. Example 或 chapter 14.5. Retry 出现异常,请重试。我还在stackoverflow 中找到了here 和here。
我试过这个:
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 是我的 Annotation,用于标记发生异常时需要重试的方法。没用...我也尝试了几种方法,例如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。
【问题讨论】:
-
您的 2 个链接用于 Spring.net
-
我知道,但他们以同样的方式解决了这个问题......
-
我需要说的是,我认为的方面,被执行到“早期”,事务的提交发生在后面,所以重试是不可能的。今晚我还尝试了 select ... for update,锁工作了,但两个客户端都收到了乐观锁异常(或陈旧数据)。
-
我发现了露天风格:google.com/codesearch/p?hl=de#xjl_JOiZ61E/repos/… 有这样的标准吗?
标签: java spring transactions aspectj optimistic-locking