正文!!!!!!!!!!!!!!!!!!
在做项目统计公告的浏览量功能时,对数据库采用了version字段,也就是乐观锁来保证数据的一致与正确性。但也导致了新的问题,当A在修改数据库数据的代码执行过程中,此时数据库的这条数据已经被B用户正好修改了,此时A用户在执行update数据时,就无法匹配条件where version = version,这样就导致这条数据无法更新到数据库中去。这就引出了重试机制。
重试机制:顾名思义就是在程序抛出异常或者自己指定的时来时进行重试来进行相应的数据操作。
重试机制实现的方法:
- 环绕通知的切面AOP
- spring-retry框架(添加依赖即可)
1.环绕通知的切面实现
①:创建自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface IsTryAgain {
}
注解名字随意。
②:创建切面
@Aspect
@Component
public class IsTryAgainAspect {
private static final Logger logger = LoggerFactory.getLogger(IsTryAgainAspect.class);
private static final int DEFAULT_MAX_RETRIES = 5;
private int maxRetries = DEFAULT_MAX_RETRIES;
// @Order(1)
@Pointcut("@annotation(IsTryAgain)")
public void tryAgainPointcut() {
}
@Around("tryAgainPointcut()")
public void doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
do {
numAttempts++;
Integer result = (Integer) pjp.proceed();//获取方法的返回值来判断,可根据实际情况修改类型
if (result > 0) {
break;
}
//等待一个随机的时间 错峰
waitForLock();
} while (numAttempts <= this.maxRetries);
MethodSignature signature = (MethodSignature)pjp.getSignature();
Method method = signature.getMethod();
logger.warn("retry failure, method: [{}]", method.toString());
}
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
//等待随机时间进行重试
private void waitForLock() {
Random random = new Random();
try {
Thread.sleep(random.nextInt(10) + 1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
贴上全部代码自己研究吧,
重点说下这个,因为有的使用异常来判断是否重试,我这里是获取方法的返回值来判断是否重试,具体可以根据自己的需求来!
因为我是update语句,返回值只会有0和1,所以可以根据实际情况来判定重试的时机!!!!
③在需要重试的方法上加上注解,一般是加在逻辑service层上
二.使用框架spring_retry实现
注:这个方法是在网上看到的,具体效果有用与否未实验,有需要自取
①:pom.xml文件添加依赖
<!--retry-->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
② :在需要重试机制的方法上添加注解
/**
* 测试重试
*
* @Retryable的参数说明: •value:抛出指定异常才会重试
* •include:和value一样,默认为空,当exclude也为空时,默认所以异常
* •exclude:指定不处理的异常
* •maxAttempts:最大重试次数,默认3次
* •backoff:重试等待策略,默认使用@Backoff,@Backoff的value默认为1000L,我们设置为2000L;
* multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试
*/
@Retryable(value = RetryException.class, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 1))
public BaseResponse testRetry(){
//逻辑关系
};
③:在业务异常处抛出指定异常,建议抛出框架定义的异常RetryException(这种就是指定异常来进行重试时机的判定)
结束!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!