需求描述
1.数据库隔离级别为RC
2.存在大量毫秒级别并发场景,RC隔离级别下的mysql去获取同样的事务版本,对同样表的修改会有被相互覆盖的情况
3.需要以方法为维度加上分布式锁,保证毫秒级别的并发里,对同一张表的操作不会有同样的版本号
4.锁应该以方法为维度,方便加在持久层(对数据库单表操作)或者直接加在服务层的方法上
代码
定义一个注解
package com.chriswei.annotation;
import com.chriswei.aspect.methodLock.IMethodLockHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 方法锁
*
* @author chriswei
* @since 1.0.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodLock {
/**
* 标识哪一个参数作为关联锁关键字
*/
String keyName() default "id";
/**
* 是否动态主键,默认是,key值将从入参获取;若否,将以keyName作为key名,而不去考虑入参。
*/
boolean isDynamicKey() default true;
/**
* redis锁的持有时间
*/
int time() default 1;
/**
* 是否需要token区分用户作为锁
* token从上下文中获取,目的是为了以上下文区作为key值去区分不同的用户
*/
boolean hasToken() default false;
/**
* redis key 前置处理器,用于对从入参中抽取的关键字进行进一步处理
* 当你面临两把锁的入参是两个不同的值,但是它们两个方法需要同一把锁的时候,可以通过这个方法作进一步处理
*/
Class<? extends IMethodLockHandler> handler() default IMethodLockHandler.class;
}
注解对应的切面类
package com.chriswei.aspect;
import com.chriswei.lock.api.ILockService;
import com.chriswei.lock.api.Mutex;
import com.chriswei.annotation.MethodLock;
import com.chriswei.aspect.methodLock.IMethodLockHandler;
import com.chriswei.txEngine.context.SpringApplicationContext;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger