马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
第一种:@EasyLock
简介
为了简化可复用注解,自己实现的注解,代码简朴随拿随用
使用方式
1.创建一个注解
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface EasyLock {
- long waitTime() default 1;
- long leaseTime() default 3;
- }
复制代码 2. 创建一个AOP切面类(异常可以自界说,这里我用的Cicada)
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang.StringUtils;
- 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.aspectj.lang.reflect.MethodSignature;
- import org.redisson.api.RLock;
- import org.redisson.api.RedissonClient;
- import org.springframework.stereotype.Component;
- import vip.lspace.agent.common.annotation.EasyLock;
- import vip.lspace.agent.common.exception.LockException;
- import javax.annotation.Resource;
- import java.util.concurrent.TimeUnit;
- @Component
- @Aspect
- @Slf4j
- public class LockAop {
- @Resource
- private LockException lockException;
- @Resource
- RedissonClient redissonClient;
- private static final String redisLockKeyParamName = "redisLockKey";
- @Pointcut("@annotation(vip.lspace.agent.common.annotation.EasyLock)")
- public void lockPointcut() {
- }
- @Around("lockPointcut()")
- public Object doAround(ProceedingJoinPoint proceedingJoinPoint) {
- log.info("EasyLock locking");
- MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
- EasyLock easyLock = methodSignature.getMethod().getAnnotation(EasyLock.class);
- Object[] args = proceedingJoinPoint.getArgs();
- String[] parameterNames = methodSignature.getParameterNames();
- String redisLockKey = "";
- for (int i = 0; i < parameterNames.length; i++) {
- if (parameterNames[i].equals(redisLockKeyParamName)) {
- redisLockKey = (String) args[i];
- }
- }
- if (StringUtils.isBlank(redisLockKey)) {
- throw lockException.lockKeyNotExist();
- }
- RLock lock = redissonClient.getLock(redisLockKey);
- try {
- if (!lock.tryLock(easyLock.waitTime(), easyLock.leaseTime(), TimeUnit.SECONDS)) {
- throw lockException.getLockTimeOut(redisLockKey);
- }
- return proceedingJoinPoint.proceed();
- } catch (Throwable e) {
- throw new RuntimeException(e);
- } finally {
- if (lock.isLocked() && lock.isHeldByCurrentThread()) {
- lock.unlock();
- log.info("当前线程{},释放锁:{}", Thread.currentThread().getId(), redisLockKey);
- }
- }
- }
复制代码- @CicadaBean(namespace = "lock")
- public interface LockException {
- @ExceptionInfo(errCode = 13001, errMessage = "没找到分布式锁key")
- CicadaException lockKeyNotExist();
- @ExceptionInfo(errCode = 13002, errMessage = "超时未获取到锁: %s")
- CicadaException getLockTimeOut(String key);
- }
复制代码 3.使用方式
留意点:
必须包含名为redisLockKey的参数,作为redis的key
- @Override
- @EasyLock(waitTime = 1,
- leaseTime = 3
- )
- @Transactional(rollbackFor = Exception.class)
- public void concurrentTest(String redisLockKey) {
- PaymentBillBacktrack paymentBillBacktrack = paymentBillBacktrackService.getById(1L);
- String refundRequestNo = paymentBillBacktrack.getMerchantRefundRequestNo();
- paymentBillBacktrack.setMerchantRefundRequestNo(String.valueOf(Integer.parseInt(refundRequestNo) + 1));
- paymentBillBacktrackService.updateById(paymentBillBacktrack);
- }
复制代码 第二种:@NiceLock
简介
大佬提供的公共组件,引包后可直接使用,使用简朴,细节代码可看nicelock: nicelock:一个注解,即可使用Java的分布式锁。(基于Redisson)
使用方式
1.引包
肯定得引入1.1.6的,甚至最新版本,否则有问题!!!
- <dependency>
- <groupId>com.suchtool</groupId>
- <artifactId>nicelock-spring-boot-starter</artifactId>
- <version>1.1.6</version>
- </dependency>
复制代码 2.使用
- @Override
- @Transactional
- @NiceLock(
- keys = {"#userId"},
- acquireTimeout = 3000L,
- exception = NiceLockLockFailException.class,
- message = "服务已完成评价,不能重复提交"
- )
- public void test(String userId) {
- System.out.println("修改订单: 用户ID=" + userId);
- }
复制代码 注解中传入了exception参数后,报错会输出message的内容,更加直观
测试方式
Apifox中的主动化测试中可以配多个线程同时执行接口,测试重复点击是否生效
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |