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

如何使用注解方式實現(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;

    /**
     * 加鎖,加鎖失敗拋默認異常 - 操作頻繁, 請稍后再試
     *
     * @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è)務代碼
        } 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();

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

    /**
     * 鎖等待時間,默認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è)務代碼
        return "";
    }
}

當然也可以自定義鎖的超時時間和等待時間

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

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

相關文章

  • Redis的大Key對持久化影響分析

    Redis的大Key對持久化影響分析

    為了保證數(shù)據(jù)的持久性,Redis提供了兩種持久化的方式,本文主要介紹了Redis的大Key對持久化影響分析,具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • Redis三種特殊數(shù)據(jù)類型的具體使用

    Redis三種特殊數(shù)據(jù)類型的具體使用

    本文主要介紹了Redis三種特殊數(shù)據(jù)類型的具體使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 如何解決Redis緩存穿透(緩存空對象、布隆過濾器)

    如何解決Redis緩存穿透(緩存空對象、布隆過濾器)

    緩存穿透是一個常見的問題,它發(fā)生當請求的數(shù)據(jù)既不在緩存中也不在數(shù)據(jù)庫中,文章通過一個查詢商品店鋪的案例,展示了如何結(jié)合這兩種方法來避免緩存穿透,首先利用布隆過濾器過濾掉不存在的id,對于誤判的情況,則采用緩存空對象的策略進行補救
    2024-11-11
  • Redis實現(xiàn)和數(shù)據(jù)庫的數(shù)據(jù)同步

    Redis實現(xiàn)和數(shù)據(jù)庫的數(shù)據(jù)同步

    本文介紹了Redis與傳統(tǒng)數(shù)據(jù)庫數(shù)據(jù)同步的幾種常見方法,包括CacheAside、WriteThrough、WriteBehind,以及如何通過分布式事務、樂觀鎖、數(shù)據(jù)過期策略和消息隊列來解決數(shù)據(jù)一致性問題,每種方法都有其適用場景和優(yōu)缺點,需要根據(jù)具體需求進行選擇
    2025-01-01
  • 關于Redis數(shù)據(jù)庫三種持久化方案介紹

    關于Redis數(shù)據(jù)庫三種持久化方案介紹

    大家好,本篇文章主要講的是關于Redis數(shù)據(jù)庫三種持久化方案介紹,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • redis初學者常見字符亂碼問題及解決方案

    redis初學者常見字符亂碼問題及解決方案

    這篇文章主要介紹了redis初學者常見字符亂碼問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Redis和Memcached的區(qū)別詳解

    Redis和Memcached的區(qū)別詳解

    這篇文章主要介紹了Redis和Memcached的區(qū)別詳解,本文從各方面總結(jié)了兩個數(shù)據(jù)庫的不同之處,需要的朋友可以參考下
    2015-03-03
  • redis中RedissonLock如何實現(xiàn)等待鎖的

    redis中RedissonLock如何實現(xiàn)等待鎖的

    本文主要介紹了redis中RedissonLock如何實現(xiàn)等待鎖的,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Redis客戶端工具之RedisInsight的下載方式

    Redis客戶端工具之RedisInsight的下載方式

    RedisInsight是Redis官方提供的圖形化客戶端工具,下載步驟包括訪問Redis官網(wǎng)、選擇RedisInsight、下載鏈接、注冊信息、安裝并測試連接
    2025-03-03
  • windows上修改redis端口號的操作步驟

    windows上修改redis端口號的操作步驟

    redis是一個開源的內(nèi)存數(shù)據(jù)結(jié)構(gòu)存儲系統(tǒng),常用做數(shù)據(jù)庫、緩存和消息代理,默認的端口號為6379,那么如何在windows上修改redis端口號,接下來本文給大家詳細介紹了windows上修改redis端口號的操作方法,需要的朋友可以參考下
    2024-02-02

最新評論

历史| 安龙县| 耿马| 浦江县| 永修县| 宣汉县| 沧源| 鹿邑县| 嘉义县| 于田县| 米泉市| 宣化县| 金昌市| 凭祥市| 鹤壁市| 罗源县| 封丘县| 航空| 贵定县| 高唐县| 山西省| 共和县| 甘洛县| 汝城县| 扶余县| 昌平区| 安乡县| 兴城市| 安龙县| 嫩江县| 兰州市| 连平县| 密云县| 宜阳县| 泾源县| 龙游县| 永德县| 烟台市| 瓮安县| 丰原市| 前郭尔|