`

并发锁事务重试机制(JPA高并发下的乐观锁异常)

 
阅读更多

 

        我的博文中,有一篇短文Java结合Junit做并发测试用例,是介绍JPA在高并发下,多个Service方法更新

同一个记录;在异常信息中有StaleObjectStateException和ObjectOptimisticLockingFailureException异常信

息。有些业务这种靠JPA维护的版本信息是可行的,如果两个不同用户同事(高并发)购买一件马丁靴鞋子,最后会更新该马丁靴在库数量,如果没有重试机制,肯定只有一个用户购买失败;可能这没有什么,用户再次提交购买就ok了;可是作为事逼可能成就人生的工程师,你一定不能容忍,于是有了重试机制。

 

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

 

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics