最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring防止重復(fù)點(diǎn)擊的兩種實(shí)現(xiàn)方法

 更新時(shí)間:2025年01月07日 10:08:14   作者:小呂學(xué)編程  
頁(yè)面重復(fù)提交導(dǎo)致的問(wèn)題就是數(shù)據(jù)被重復(fù)保存,我們經(jīng)常會(huì)誤觸點(diǎn)擊兩次,所以本文小編給大家介紹了Spring防止重復(fù)點(diǎn)擊的兩種實(shí)現(xiàn)方法,需要的朋友可以參考下

第一種:@EasyLock

簡(jiǎn)介

為了簡(jiǎn)化可復(fù)用注解,自己實(shí)現(xiàn)的注解,代碼簡(jiǎn)單隨拿隨用

使用方式

1.創(chuàng)建一個(gè)注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EasyLock {
    long waitTime() default 1;
    long leaseTime() default 3;
}

 2. 創(chuàng)建一個(gè)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("當(dāng)前線程{},釋放鎖:{}", Thread.currentThread().getId(), redisLockKey);
            }
        }
    }
@CicadaBean(namespace = "lock")
public interface LockException {
    @ExceptionInfo(errCode = 13001, errMessage = "沒(méi)找到分布式鎖key")
    CicadaException lockKeyNotExist();
 
    @ExceptionInfo(errCode = 13002, errMessage = "超時(shí)未獲取到鎖: %s")
    CicadaException getLockTimeOut(String key);
}

3.使用方式

 注意點(diǎn):

必須包含名為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

簡(jiǎn)介

大佬提供的公共組件,引包后可直接使用,使用簡(jiǎn)單

使用方式

1.引包

一定得引入1.1.6的,甚至最新版本,不然有問(wèn)題!??!

<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ù)已完成評(píng)價(jià),不能重復(fù)提交"
    )
    public void test(String userId) {
        System.out.println("修改訂單: 用戶ID=" + userId);
    }

注解中傳入了exception參數(shù)后,報(bào)錯(cuò)會(huì)輸出message的內(nèi)容,更加直觀 

測(cè)試方式

Apifox中的自動(dòng)化測(cè)試中可以配多個(gè)線程同時(shí)執(zhí)行接口,測(cè)試重復(fù)點(diǎn)擊是否生效

到此這篇關(guān)于Spring防止重復(fù)點(diǎn)擊的兩種實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)Spring防止重復(fù)點(diǎn)擊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java解決約瑟夫問(wèn)題代碼實(shí)例

    Java解決約瑟夫問(wèn)題代碼實(shí)例

    這篇文章主要介紹了Java解決約瑟夫(環(huán))問(wèn)題的代碼實(shí)例,決約瑟問(wèn)題貌似經(jīng)常出現(xiàn)在面試題中,需要的朋友可以參考下
    2014-03-03
  • Java 使用Filter實(shí)現(xiàn)用戶自動(dòng)登陸

    Java 使用Filter實(shí)現(xiàn)用戶自動(dòng)登陸

    這篇文章主要介紹了Java 使用Filter實(shí)現(xiàn)用戶自動(dòng)登陸的方法,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-05-05
  • Java源碼刨析之ArrayQueue

    Java源碼刨析之ArrayQueue

    在本篇文章當(dāng)中主要給大家介紹一個(gè)比較簡(jiǎn)單的JDK為我們提供的容器ArrayQueue,這個(gè)容器主要是用數(shù)組實(shí)現(xiàn)的一個(gè)單向隊(duì)列,整體的結(jié)構(gòu)相對(duì)其他容器來(lái)說(shuō)就比較簡(jiǎn)單了
    2022-07-07
  • java中的4種循環(huán)方法示例詳情

    java中的4種循環(huán)方法示例詳情

    大家好,本篇文章主要講的是java中的4種循環(huán)方法示例詳情,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • JAVA實(shí)現(xiàn)微信APPV3支付保姆級(jí)教程

    JAVA實(shí)現(xiàn)微信APPV3支付保姆級(jí)教程

    微信實(shí)現(xiàn)支付功能與支付寶實(shí)現(xiàn)支付功能是相似的,這篇文章主要介紹了JAVA實(shí)現(xiàn)微信APPV3支付的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • Java的MyBatis框架中XML映射緩存的使用教程

    Java的MyBatis框架中XML映射緩存的使用教程

    MyBatis程序在做好XML映射后能夠有緩存的功能,這樣映射過(guò)SQL語(yǔ)句的配置以后就可以拿過(guò)來(lái)直接用了,這里我們來(lái)一起總結(jié)一下Java的MyBatis框架中XML映射緩存的使用教程
    2016-06-06
  • Java多線程中Thread.currentThread()和this的區(qū)別詳解

    Java多線程中Thread.currentThread()和this的區(qū)別詳解

    這篇文章主要介紹了Java多線程中Thread.currentThread()和this的區(qū)別詳解,Thread.currentThread()方法返回的是對(duì)當(dāng)前正在執(zhí)行的線程對(duì)象的引用,this代表的是當(dāng)前調(diào)用它所在函數(shù)所屬的對(duì)象的引用,需要的朋友可以參考下
    2023-08-08
  • Java實(shí)現(xiàn)簡(jiǎn)單連連看游戲

    Java實(shí)現(xiàn)簡(jiǎn)單連連看游戲

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單連連看游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Echarts+SpringMvc顯示后臺(tái)實(shí)時(shí)數(shù)據(jù)

    Echarts+SpringMvc顯示后臺(tái)實(shí)時(shí)數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了Echarts+SpringMvc顯示后臺(tái)實(shí)時(shí)數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • 在idea中顯示springboot面板的方法

    在idea中顯示springboot面板的方法

    這篇文章主要介紹了在idea中顯示springboot面板的方法方便啟動(dòng)調(diào)試,本文通過(guò)代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11

最新評(píng)論

城固县| 兖州市| 抚顺县| 荣昌县| 汝南县| 漠河县| 宜兰县| 望城县| 霍山县| 定边县| 勃利县| 金川县| 静海县| 湖口县| 屯昌县| 甘德县| 黄骅市| 宁德市| 揭西县| 普安县| 明星| 呼玛县| 遂宁市| 永平县| 铜山县| 神农架林区| 武宣县| 青海省| 克什克腾旗| 华蓥市| 自治县| 铜山县| 竹北市| 德安县| 留坝县| 普定县| 稻城县| 泰安市| 青河县| 蒲城县| 夏邑县|