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

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

 更新時(shí)間:2022年07月22日 09:01:23   作者:??編程大椰子?  
這篇文章主要介紹了如何使用注解方式實(shí)現(xiàn)Redis分布式鎖,文章圍繞主題展開詳細(xì)的內(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)                // 建立連接超時(shí)時(shí)間
                .setTimeout(2000)                       // 執(zhí)行命令的超時(shí)時(shí)間, 從命令發(fā)送成功時(shí)開始計(jì)時(shí)
                .setRetryAttempts(2)                    // 命令執(zhí)行失敗重試次數(shù)
                .setRetryInterval(1000);                // 命令重試發(fā)送時(shí)間間隔

        return Redisson.create(config);
    }
}

這樣我們就可以在項(xiàng)目里面使用 Redisson 了。

編寫 Redisson 分布式鎖工具類

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

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

    @Resource
    private RedissonClient redisson;

    /**
     * 加鎖,加鎖失敗拋默認(rèn)異常 - 操作頻繁, 請(qǐng)稍后再試
     *
     * @param key        加鎖唯一key
     * @param expireTime 鎖超時(shí)時(shí)間 毫秒
     * @param waitTime   加鎖最長等待時(shí)間 毫秒
     * @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        鎖超時(shí)時(shí)間 毫秒
     * @param waitTime          加鎖最長等待時(shí)間 毫秒
     * @param exceptionSupplier 加鎖失敗時(shí)拋該異常,傳null時(shí)加鎖失敗不拋異常
     * @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, 鎖超時(shí)時(shí)間:5s, 鎖等待時(shí)間:50ms
        LockResult lockResult = lockManager.lock(userId, 5000, 50);

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

        return "";
    }
}

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

聲明注解 @Lock

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

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

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

}

注解解析類

@Aspect
@Component
@Slf4j
public class LockAnnotationParser {

    @Resource
    private LockManager lockManager;

    /**
     * 定義切點(diǎn)
     */
    @Pointcut(value = "@annotation(Lock)")
    private void cutMethod() {
    }
		
    /**
     * 切點(diǎn)邏輯具體實(shí)現(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 表達(dá)式并返回其值
     */
    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)然也可以自定義鎖的超時(shí)時(shí)間和等待時(shí)間

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

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

相關(guān)文章

  • Redis的大Key對(duì)持久化影響分析

    Redis的大Key對(duì)持久化影響分析

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    windows上修改redis端口號(hào)的操作步驟

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

最新評(píng)論

资溪县| 岳阳市| 安陆市| 蒙自县| 桐柏县| 横峰县| 通化市| 延庆县| 高雄市| 普洱| 永年县| 靖远县| 抚宁县| 屏山县| 南城县| 五峰| 康马县| 个旧市| 通城县| 海阳市| 密山市| 绵竹市| 江山市| 科尔| 敦煌市| 沅陵县| 大同市| 凤山县| 四子王旗| 托里县| 揭东县| 正定县| 宣恩县| 洛南县| 宜丰县| 元江| 瑞昌市| 和硕县| 旌德县| 宁乡县| 蓬溪县|