樂觀鎖:
model實體類加version字段
@JsonProperty("_version")
@Column(name = "version", nullable = false)
@Version
private Long version = 0L;
問題場景
先在庫裏查詢出該實體,轉化爲持久態,在這時庫裏的該數據被修改了,並且version發生變更,此時持久態實體進行save操作,會觸發樂觀鎖異常。
1:解決方案
定義Aspectj攔截器,指定方法發生樂觀鎖異常時,進行重試。
2:show coding.
(1) 因爲不是所有方法發生樂觀鎖異常都是需要重試機制的,所以需要先定義切面接口定義IsTryAgain
/**
* 自定義嘗試切面接口
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface IsTryAgain {
// marker annotation
}
(2)Service接口方法加上切面接口定義
/**
* 併發樂觀鎖需要重試的方法
*/
@IsTryAgain
boolean TryAgainMethod() throws Exception;
(3)定義Aspectj切面攔截器
定義重試切面方法,是爲了發生樂觀鎖異常時在一個全新的事務裏提交上一次的操作,直到達到重試上限;因此切面實現 org.springframework.core.Ordered 接口,這樣我們就可以把切面的優先級設定爲高於事務通知 。
@Aspect
public class SystemArchitecture {
@Pointcut("execution(* myapp..service..*(..))")
public void businessService() {
}
}
@Aspect
class ConcurrentOperationExecutor implements Ordered {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
@Around("myapp.SystemArchitecture.businessService()")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}
catch(PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
}while(numAttempts <= this.maxRetries);
throw lockFailureException;
}
}
3:更多
AOP知識,Spring AOP和Aspectj的知識。