高併發鎖事務重試機制(JPA高併發下的樂觀鎖異常)

樂觀鎖:

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的知識。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章