Spring防止重復(fù)點擊的兩種實現(xiàn)方法
第一種:@EasyLock
簡介
為了簡化可復(fù)用注解,自己實現(xiàn)的注解,代碼簡單隨拿隨用
使用方式
1.創(chuàng)建一個注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EasyLock { long waitTime() default 1; long leaseTime() default 3; }
2. 創(chuàng)建一個AOP切面類(異??梢宰远x,這里我用的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("當(dāng)前線程{},釋放鎖:{}", 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的參數(shù),作為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
簡介
大佬提供的公共組件,引包后可直接使用,使用簡單
使用方式
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 = "服務(wù)已完成評價,不能重復(fù)提交" ) public void test(String userId) { System.out.println("修改訂單: 用戶ID=" + userId); }
注解中傳入了exception參數(shù)后,報錯會輸出message的內(nèi)容,更加直觀
測試方式
Apifox中的自動化測試中可以配多個線程同時執(zhí)行接口,測試重復(fù)點擊是否生效
到此這篇關(guān)于Spring防止重復(fù)點擊的兩種實現(xiàn)方法的文章就介紹到這了,更多相關(guān)Spring防止重復(fù)點擊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java存儲過程調(diào)用CallableStatement的方法
這篇文章主要介紹了Java存儲過程調(diào)用CallableStatement的方法,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下2020-11-11Java內(nèi)存模型之重排序的相關(guān)知識總結(jié)
重排序是指編譯器和處理器為了優(yōu)化性能而對指令序列進(jìn)行重新排序的一種手段,文中詳細(xì)介紹了Java重排序的相關(guān)知識,需要的朋友可以參考下2021-06-06Kotlin 內(nèi)聯(lián)函數(shù)詳解及實例
這篇文章主要介紹了Kotlin 內(nèi)聯(lián)函數(shù)詳解及實例的相關(guān)資料,需要的朋友可以參考下2017-06-06