欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何使用注解方式實現(xiàn)?Redis?分布式鎖

 更新時間:2022年07月22日 09:01:23   作者:??編程大椰子?  
這篇文章主要介紹了如何使用注解方式實現(xiàn)Redis分布式鎖,文章圍繞主題展開詳細的內(nèi)容介紹,教大家如何優(yōu)雅的使用Redis分布式鎖,感興趣的小伙伴可以參考一下

引入 Redisson

<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson-spring-boot-starter</artifactId>
  <version>3.14.1</version>
</dependency>

初始化 Redisson

@Configuration
public class RedissonConfiguration {
  
    // 此處更換自己的 Redis 地址即可
    @Value("${redis.addr}")
    private String addr;

    @Bean
    public RedissonClient redisson() {
        Config config = new Config();
        config.useSingleServer()
                .setAddress(String.format("%s%s", "redis://", addr))
                .setConnectionPoolSize(64)              // 連接池大小
                .setConnectionMinimumIdleSize(8)        // 保持最小連接數(shù)
                .setConnectTimeout(1500)                // 建立連接超時時間
                .setTimeout(2000)                       // 執(zhí)行命令的超時時間, 從命令發(fā)送成功時開始計時
                .setRetryAttempts(2)                    // 命令執(zhí)行失敗重試次數(shù)
                .setRetryInterval(1000);                // 命令重試發(fā)送時間間隔

        return Redisson.create(config);
    }
}

這樣我們就可以在項目里面使用 Redisson 了。

編寫 Redisson 分布式鎖工具類

Redis 分布式鎖的工具類,主要是調(diào)用 Redisson 客戶端實現(xiàn),做了輕微的封裝。

@Service
@Slf4j
public class LockManager {
    /**
     * 最小鎖等待時間
     */
    private static final int MIN_WAIT_TIME = 10;

    @Resource
    private RedissonClient redisson;

    /**
     * 加鎖,加鎖失敗拋默認(rèn)異常 - 操作頻繁, 請稍后再試
     *
     * @param key        加鎖唯一key
     * @param expireTime 鎖超時時間 毫秒
     * @param waitTime   加鎖最長等待時間 毫秒
     * @return LockResult  加鎖結(jié)果
     */
    public LockResult lock(String key, long expireTime, long waitTime) {
        return lock(key, expireTime, waitTime, () -> new BizException(ResponseEnum.COMMON_FREQUENT_OPERATION_ERROR));
    }
    /**
     * 加鎖,加鎖失敗拋異常 - 自定義異常
     *
     * @param key               加鎖唯一key
     * @param expireTime        鎖超時時間 毫秒
     * @param waitTime          加鎖最長等待時間 毫秒
     * @param exceptionSupplier 加鎖失敗時拋該異常,傳null時加鎖失敗不拋異常
     * @return LockResult  加鎖結(jié)果
     */
    private LockResult lock(String key, long expireTime, long waitTime, Supplier<BizException> exceptionSupplier) {
        if (waitTime < MIN_WAIT_TIME) {
            waitTime = MIN_WAIT_TIME;
        }
        LockResult result = new LockResult();
        try {
            RLock rLock = redisson.getLock(key);
            try {
                if (rLock.tryLock(waitTime, expireTime, TimeUnit.MILLISECONDS)) {
                    result.setLockResultStatus(LockResultStatus.SUCCESS);
                    result.setRLock(rLock);
                } else {
                    result.setLockResultStatus(LockResultStatus.FAILURE);
                }
            } catch (InterruptedException e) {
                log.error("Redis 獲取分布式鎖失敗, key: {}, e: {}", key, e.getMessage());
                result.setLockResultStatus(LockResultStatus.EXCEPTION);
                rLock.unlock();
            }
        } catch (Exception e) {
            log.error("Redis 獲取分布式鎖失敗, key: {}, e: {}", key, e.getMessage());
            result.setLockResultStatus(LockResultStatus.EXCEPTION);
        }

        if (exceptionSupplier != null && LockResultStatus.FAILURE.equals(result.getLockResultStatus())) {
            log.warn("Redis 加鎖失敗, key: {}", key);
            throw exceptionSupplier.get();
        }

        log.info("Redis 加鎖結(jié)果:{}, key: {}", result.getLockResultStatus(), key);

        return result;
    }
    /**
     * 解鎖
     */
    public void unlock(RLock rLock) {
        try {
            rLock.unlock();
        } catch (Exception e) {
            log.warn("Redis 解鎖失敗", e);
        }
    }
}

加鎖結(jié)果狀態(tài)枚舉類。

public enum LockResultStatus {
    /**
     * 通信正常,并且加鎖成功
     */
    SUCCESS,
    /**
     * 通信正常,但獲取鎖失敗
     */
    FAILURE,
    /**
     * 通信異常和內(nèi)部異常,鎖狀態(tài)未知
     */
    EXCEPTION;
}

加鎖結(jié)果類封裝了加鎖狀態(tài)和RLock。

@Setter
@Getter
public class LockResult {

    private LockResultStatus lockResultStatus;

    private RLock rLock;
}

自此我們就可以使用分布式鎖了,使用方式:

@Service
@Slf4j
public class TestService {

    @Resource
    private LockManager lockManager;

    public String test(String userId) {
        // 鎖:userId, 鎖超時時間:5s, 鎖等待時間:50ms
        LockResult lockResult = lockManager.lock(userId, 5000, 50);

        try {
            //  業(yè)務(wù)代碼
        } finally {
            lockManager.unlock(lockResult.getRLock());
        }

        return "";
    }
}

為了防止程序發(fā)生異常,所以每次我們都需要在finally代碼塊里手動釋放鎖。為了更方便優(yōu)雅的使用 Redis 分布式鎖,我們使用注解方式實現(xiàn)下。

聲明注解 @Lock

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Lock {
    /**
     * lock key
     */
    String value();

    /**
     * 鎖超時時間,默認(rèn)5000ms
     */
    long expireTime() default 5000L;

    /**
     * 鎖等待時間,默認(rèn)50ms
     */
    long waitTime() default 50L;

}

注解解析類

@Aspect
@Component
@Slf4j
public class LockAnnotationParser {

    @Resource
    private LockManager lockManager;

    /**
     * 定義切點
     */
    @Pointcut(value = "@annotation(Lock)")
    private void cutMethod() {
    }
		
    /**
     * 切點邏輯具體實現(xiàn)
     */
    @Around(value = "cutMethod() && @annotation(lock)")
    public Object parser(ProceedingJoinPoint point, Lock lock) throws Throwable {
        String value = lock.value();
        if (isEl(value)) {
            value = getByEl(value, point);
        }
        LockResult lockResult = lockManager.lock(getRealLockKey(value), lock.expireTime(), lock.waitTime());
        try {
            return point.proceed();
        } finally {
            lockManager.unlock(lockResult.getRLock());
        }
    }

    /**
     * 解析 SpEL 表達式并返回其值
     */
    private String getByEl(String el, ProceedingJoinPoint point) {
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        String[] paramNames = getParameterNames(method);
        Object[] arguments = point.getArgs();
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(el);
        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < arguments.length; i++) {
            context.setVariable(paramNames[i], arguments[i]);
        }
        return expression.getValue(context, String.class);
    }
    /**
     * 獲取方法參數(shù)名列表
     */
    private String[] getParameterNames(Method method) {
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        return u.getParameterNames(method);
    }
    private boolean isEl(String str) {
        return str.contains("#");
    }
    /**
     * 鎖鍵值
     */
    private String getRealLockKey(String value) {
        return String.format("lock:%s", value);
    }
}

下面使用注解方式使用分布式鎖:

@Service
@Slf4j
public class TestService {
    @Lock("'test_'+#user.userId")
    public String test(User user) {
        // 業(yè)務(wù)代碼
        return "";
    }
}

當(dāng)然也可以自定義鎖的超時時間和等待時間

@Service
@Slf4j
public class TestService {
    @Lock(value = "'test_'+#user.userId", expireTime = 3000, waitTime = 30)
    public String test(User user) {
        // 業(yè)務(wù)代碼
        return "";
    }
}

到此這篇關(guān)于如何使用注解方式實現(xiàn) Redis 分布式鎖的文章就介紹到這了,更多相關(guān)Redis 分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis 緩存實現(xiàn)存儲和讀取歷史搜索關(guān)鍵字的操作方法

    Redis 緩存實現(xiàn)存儲和讀取歷史搜索關(guān)鍵字的操作方法

    這篇文章主要介紹了Redis 緩存實現(xiàn)存儲和讀取歷史搜索關(guān)鍵字,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • redis使用watch秒殺搶購實現(xiàn)思路

    redis使用watch秒殺搶購實現(xiàn)思路

    這篇文章主要為大家詳細介紹了redis使用watch秒殺搶購的實現(xiàn)思路,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 關(guān)于使用IDEA的springboot框架往Redis里寫入數(shù)據(jù)亂碼問題

    關(guān)于使用IDEA的springboot框架往Redis里寫入數(shù)據(jù)亂碼問題

    這篇文章主要介紹了用IDEA的springboot框架往Redis里寫入數(shù)據(jù)亂碼問題,本文給大家分享解決方法通過圖文示例相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • redis-cli登錄遠程redis服務(wù)并批量導(dǎo)入數(shù)據(jù)

    redis-cli登錄遠程redis服務(wù)并批量導(dǎo)入數(shù)據(jù)

    本文主要介紹了redis-cli登錄遠程redis服務(wù)并批量導(dǎo)入數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-10-10
  • 淺析Redis中紅鎖RedLock的實現(xiàn)原理

    淺析Redis中紅鎖RedLock的實現(xiàn)原理

    RedLock?是一種分布式鎖的實現(xiàn)算法,由?Redis?的作者?Salvatore?Sanfilippo(也稱為?Antirez)提出,本文主要為大家詳細介紹了紅鎖RedLock的實現(xiàn)原理,感興趣的可以了解下
    2024-02-02
  • 淺談Redis緩存擊穿、緩存穿透、緩存雪崩的解決方案

    淺談Redis緩存擊穿、緩存穿透、緩存雪崩的解決方案

    這篇文章主要介紹了淺談Redis緩存擊穿、緩存穿透、緩存雪崩的解決方案,緩存是分布式系統(tǒng)中的重要組件,主要解決在高并發(fā)、大數(shù)據(jù)場景下,熱點數(shù)據(jù)訪問的性能問題,需要的朋友可以參考下
    2023-03-03
  • redis樂觀鎖與悲觀鎖的實戰(zhàn)?

    redis樂觀鎖與悲觀鎖的實戰(zhàn)?

    Redis提供了兩種鎖機制,即樂觀鎖和悲觀鎖。本文主要介紹了redis樂觀鎖與悲觀鎖的實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Spring?redis使用報錯Read?timed?out排查及解決過程

    Spring?redis使用報錯Read?timed?out排查及解決過程

    項目使用spring集成redis,偶爾會出現(xiàn)read timed out的情況,剛開始以為是網(wǎng)絡(luò)不穩(wěn)定引起的,后面發(fā)現(xiàn)影響業(yè)務(wù)測試的準(zhǔn)確性,這篇文章主要給大家介紹了關(guān)于Spring redis使用報錯Read timed out排查及解決過程的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • Redis并發(fā)問題解決方案

    Redis并發(fā)問題解決方案

    在當(dāng)前的互聯(lián)網(wǎng)環(huán)境中,高并發(fā)業(yè)務(wù)場景十分常見,本文就來介紹一下Redis并發(fā)問題解決方案,具有一定的參考價值,感興趣的可以了解一下
    2023-11-11
  • Redis中List列表常用命令總結(jié)

    Redis中List列表常用命令總結(jié)

    Redis中的List API提供了一些操作列表的命令,這篇文章主要給大家介紹了關(guān)于Redis中List列表常用命令的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-03-03

最新評論