StaleObjectStateExceptions可能是在具有多个服务器/线程的应用程序上使用Hibernate的不可避免的部分,并且通常的做法是让失败者以安全的方式短暂延迟后重试。 为了最佳实践的利益,我想创建一个强制执行安全性的框架,这样,如果重试会导致数据丢失,它将被中止并抛出异常,以迫使开发人员调查对象为何具有主题的字段。适应比赛条件并进行相应修复。
不幸的是,到目前为止,我生产的产品感觉欠佳,并且包含了我认为很多样板代码,这意味着其他开发人员不太可能在需要时使用它。 下面的ExampleRetryableUpdate如何进行改进,特别是对于具有多个字段要同时更新的Update Runnable?
public class ExampleRetryableUpdate extends SafeRetryableUpdateRunnable<Model>{
private Long id;
private String originalState;
private String targetState;
public ExampleRetryableUpdate(Model targetState, Model currentState){
this.originalState = currentState.getFieldToUpdate();
this.targetState = targetState.getFieldToUpdate();
}
@Override
boolean safeToUpdate(Model current) {
return originalState.equals(current.getFieldToUpdate());
}
@Override
String getStaleFields(Model current) {
StringBuilder sb = new StringBuilder();
if(!this.originalState.equals(current.getFieldToUpdate())){
sb.append("FieldToUpdate differs: Stale - ");
sb.append(this.originalState);
sb.append(", Current - ");
sb.append(current.getFieldToUpdate());
}
//Repeatable for each relevant field
return sb.toString();
}
@Override
public void run() {
try{
Model current = Model.findById(id);
if(safeToUpdate(current)){
current.setFieldToUpdate(targetState);
Model.persist(current);
} else{
throw new UnsafeRetryException(getStaleFields(current));
}
} catch (StaleObjectStateException ex){
System.out.println("Failed due to StaleObject exception, may retry.");
throw ex;
}
}
}
上下文类:
public abstract class SafeRetryableUpdateRunnable<T> implements Runnable {
abstract boolean safeToUpdate(T Model);
abstract String getStaleFields(T current);
}
public class Model {
private Long id;
private String fieldToUpdate;
private String irrelevantField;
private Integer oca;
public String getFieldToUpdate() {
return fieldToUpdate;
}
public void setFieldToUpdate(String fieldToUpdate) {
this.fieldToUpdate = fieldToUpdate;
}
...
}
public class BusinessLogicClass {
public boolean someMethod() throws InterruptedException {
//Business logic
//...
//Get current from Db, create a copy and alter fieldToUpdate
//...
ExampleRetryableUpdate runnable = new ExampleRetryableUpdate(targetState, currentState);
int i = 0;
do{
try{
runnable.run();
return true;
} catch(StaleObjectStateException ex){
System.out.println("Expected, potentially retryable.");
Thread.sleep(1000L);
} catch(UnsafeRetryException ex){
System.out.println("Field has been updated by an alternate thread/server. Aborting.");
return false;
}
}while (i++ <= 3);
return false;
}
}