解决并发问题,数据库常用的两把锁!( 三 )


 String url = "http://localhost:8888/catalogRetry";
 for(int i = 0; i < 100; i++) {
 final int num = i;
 new Thread(() -> {
 MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 params.add("catalogId", "1");
 params.add("user", "user" + num);
 String result = testRestTemplate.postForObject(url, params, String.class);
 System.out.println("-------------" + result);
 }
 ).start();
 }
 }
}
调用100次,即一个商品可以浏览一百次,采用悲观锁,catalog表的数据都是100,并且browse表也是100条记录 。采用乐观锁的时候,因为版本号的匹配关系,那么会有一些记录丢失,但是这两个表的数据是可以对应上的 。
乐观锁失败后会抛出ObjectOptimisticLockingFailureException,那么我们就针对这块考虑一下重试,下面我就自定义了一个注解,用于做切面 。
package com.hqs.dblock.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RetryOnFailure {
}
针对注解进行切面,见如下代码 。我设置了最大重试次数5,然后超过5次后就不再重试 。
package com.hqs.dblock.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.hibernate.StaleObjectStateException;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
public class RetryAspect {
 public static final int MAX_RETRY_TIMES = 5;//max retry times
 @Pointcut("@annotation(com.hqs.dblock.annotation.RetryOnFailure)") //self-defined pointcount for RetryOnFailure
 public void retryOnFailure(){}
 @Around("retryOnFailure()") //around can be execute before and after the point
 public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
 int attempts = 0;
 do {
 attempts++;
 try {
 pjp.proceed();
 } catch (Exception e) {
 if(e instanceof ObjectOptimisticLockingFailureException ||
 e instanceof StaleObjectStateException) {
 log.info("retrying....times:{}", attempts);
 if(attempts > MAX_RETRY_TIMES) {
 log.info("retry excceed the max times..");
 throw e;
 }
 }
 }
 } while (attempts < MAX_RETRY_TIMES);
 return null;
 }
}
大致思路是这样了 。
 
【解决并发问题,数据库常用的两把锁!】


推荐阅读