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

spring-data-redis自定義實現看門狗機制

 更新時間:2024年03月04日 08:53:19   作者:皮卡沖撞  
redission看門狗機制是解決分布式鎖的續(xù)約問題,本文主要介紹了spring-data-redis自定義實現看門狗機制,具有一定的參考價值,感興趣的可以了解一下

前言

項目中使用redis分布式鎖解決了點贊和樓層排序得問題,所以這里就對這個redis得分布式鎖進行了學習,一般使用得是redission提供得分布式鎖解決得這個問題,但是知其然更要知其所以然,所以自己就去找了一些資料以及也實踐了一下就此記錄分享一下。

redission分布式鎖看門狗機制簡單流程圖

在這里插入圖片描述

spring-data-redis實現看門狗機制指南開始

引入依賴

        <!--redis的依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--json工具包-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.60</version>
        </dependency>      

配置redis連接以及基礎配置

spring:
  redis:
    host: localhost
    port: 6379
    lettuce:
      timeout: 200000 
    database: 1

在Spring Boot的配置類中創(chuàng)建一個RedisTemplate的Bean:

@Configuration
public class RedisConfig {


    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        // 我們?yōu)榱俗约洪_發(fā)方便,一般直接使用 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(connectionFactory);
        // Json序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String 的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

實現redis分布式鎖工具類

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class RedisLockUtils {
    @Resource
    private RedisTemplate redisTemplate;
    private volatile static Map<String, LockInfo> lockInfoMap = new ConcurrentHashMap<>();
    private static final Long SUCCESS = 1L;
    public static class LockInfo {
        private String key;
        private String value;
        private int expireTime;
        //更新時間
        private long renewalTime;
        //更新間隔
        private long renewalInterval;
        public static LockInfo getLockInfo(String key, String value, int expireTime) {
            LockInfo lockInfo = new LockInfo();
            lockInfo.setKey(key);
            lockInfo.setValue(value);
            lockInfo.setExpireTime(expireTime);
            lockInfo.setRenewalTime(System.currentTimeMillis());
            lockInfo.setRenewalInterval(expireTime*1000 *2 / 3);
            return lockInfo;
        }

        public String getKey() {
            return key;
        }
        public void setKey(String key) {
            this.key = key;
        }
        public String getValue() {
            return value;
        }
        public void setValue(String value) {
            this.value = value;
        }
        public int getExpireTime() {
            return expireTime;
        }
        public void setExpireTime(int expireTime) {
            this.expireTime = expireTime;
        }
        public long getRenewalTime() {
            return renewalTime;
        }
        public void setRenewalTime(long renewalTime) {
            this.renewalTime = renewalTime;
        }
        public long getRenewalInterval() {
            return renewalInterval;
        }
        public void setRenewalInterval(long renewalInterval) {
            this.renewalInterval = renewalInterval;
        }
    }

    /**
     * 使用lua腳本更新redis鎖的過期時間
     * @param lockKey
     * @param value
     * @return 成功返回true, 失敗返回false
     */
    public boolean renewal(String lockKey, String value, int expireTime) {
        String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end";
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();
        redisScript.setResultType(Boolean.class);
        redisScript.setScriptText(luaScript);
        List<String> keys = new ArrayList<>();
        keys.add(lockKey);

        Object result = redisTemplate.execute(redisScript, keys, value, expireTime);
        log.info("更新redis鎖的過期時間:{}", result);
        return (boolean) result;
    }

    /**
     * @param lockKey    鎖
     * @param value      身份標識(保證鎖不會被其他人釋放)
     * @param expireTime 鎖的過期時間(單位:秒)
     * @return 成功返回true, 失敗返回false
     */
    public boolean lock(String lockKey, String value, int expireTime) {
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(lockKey, value, expireTime, TimeUnit.SECONDS);
        if(aBoolean){
            lockInfoMap.put(String.valueOf(Thread.currentThread().getId()),LockInfo.getLockInfo(lockKey,value,expireTime));
        }
        return aBoolean;
    }

    /**
     * redisTemplate解鎖
     * @param key
     * @param value
     * @return 成功返回true, 失敗返回false
     */
    public boolean unlock2(String key, String value) {
        Object currentValue = redisTemplate.opsForValue().get(key);
        boolean result = false;
        if (StringUtils.isNotEmpty(String.valueOf(currentValue)) && currentValue.equals(value)) {
            lockInfoMap.remove(String.valueOf(Thread.currentThread().getId()));
            result = redisTemplate.opsForValue().getOperations().delete(key);
        }
        return result;
    }

    /**
     * 定時去檢查redis鎖的過期時間
     */
    @Scheduled(fixedRate = 1000)
    @Async("redisExecutor")
    public void renewal() {
        long now = System.currentTimeMillis();
        for (Map.Entry<String, LockInfo> lockInfoEntry : lockInfoMap.entrySet()) {
            LockInfo lockInfo = lockInfoEntry.getValue();
            System.out.println("++"+lockInfo.key);
            if (lockInfo.getRenewalTime() + lockInfo.getRenewalInterval() < now) {
                renewal(lockInfo.getKey(), lockInfo.getValue(), lockInfo.getExpireTime());
                lockInfo.setRenewalTime(now);
                log.info("lockInfo {}", JSON.toJSONString(lockInfo));
            }
        }
    }

    /**
     * 分布式鎖設置單獨線程池
     * @return
     */
    @Bean("redisExecutor")
    public ThreadPoolTaskExecutor redisExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(1);
        executor.setQueueCapacity(1);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("redis-renewal-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
        executor.initialize();
        return executor;
    }
}

這個類是一個用于實現分布式鎖的工具類,主要提供了以下功能:

  • renewal() 方法:定時檢查并更新 Redis 鎖的過期時間。該方法使用 @Scheduled 注解進行定時執(zhí)行,通過遍歷 lockInfoMap 中保存的鎖信息,判斷是否需要更新鎖的過期時間,并調用 renewal() 方法進行更新。

  • renewal(String lockKey, String value, int expireTime) 方法:使用 Lua 腳本更新 Redis 鎖的過期時間。該方法首先定義了一個 Lua 腳本,然后使用 redisTemplate.execute() 方法執(zhí)行該腳本,并傳入相應的參數。如果執(zhí)行成功,則返回 true,否則返回 false。

  • lock(String lockKey, String value, int expireTime) 方法:獲取分布式鎖。該方法使用 Redis 的 setIfAbsent() 方法嘗試將鎖的鍵值對存儲到 Redis 中,并設置相應的過期時間。如果存儲成功,則返回 true,表示獲取鎖成功;否則返回 false,表示獲取鎖失敗。

  • unlock2(String key, String value) 方法:釋放分布式鎖。該方法首先獲取 Redis 中當前的鎖值,然后判斷鎖值是否和傳入的 value 相等。如果相等,則從 lockInfoMap 中移除鎖信息,并調用 Redis 的 delete() 方法刪除鎖的鍵值對。最后返回刪除結果,表示是否成功釋放鎖。

  • redisExecutor() 方法:配置一個單獨的線程池用于執(zhí)行 renewal() 方法。該方法創(chuàng)建一個 ThreadPoolTaskExecutor 對象,并設置相關的屬性,如核心線程數、最大線程數、隊列容量等。

直接失敗和鎖重試機制實現

直接失敗的方式,就是調用獲取鎖的方法判斷是否加鎖成功,失敗則直接中斷方法執(zhí)行返回

    @GetMapping("/test2")
    public Object test2(){
        boolean a = redisLockUtils.lock("A", "111", 5);
        if(!a){
            return "獲取鎖失敗";
        }
        try{
            System.out.println("執(zhí)行開始-------------------test2");
            TimeUnit.SECONDS.sleep(12);
            System.out.println("執(zhí)行結束-------------------test2");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {

            redisLockUtils.unlock2("A","111");
            System.out.println("釋放鎖-----------------------test2");
        }
        return null;
   }

鎖重試,這里是封裝了獲取鎖的方法,加入了一個重試次數的限制,通過使用while循環(huán)去嘗試獲取鎖。

private Boolean getLock(int tryNum, String key, String value, int exp) throws InterruptedException {
    int i = 0; // 初始化計數器,記錄嘗試獲取鎖的次數
    boolean flag = false; // 初始化標志變量,表示獲取鎖的結果

    while (true) { // 循環(huán)進行嘗試獲取鎖的操作
        if (i == tryNum) { // 判斷是否達到嘗試獲取鎖的最大次數
            return flag; // 返回當前的獲取鎖結果
        }

        flag = redisLockUtils.lock(key, value, exp); // 嘗試獲取鎖,返回是否成功獲取到鎖的結果

        if (flag) { // 如果成功獲取到鎖
            return flag; // 直接返回獲取鎖結果為 true
        } else { // 如果未能成功獲取到鎖
            i++; // 計數器加一,表示已經嘗試了一次獲取鎖的操作
            TimeUnit.SECONDS.sleep(1); // 暫停一秒鐘,等待一段時間后再進行下一次獲取鎖的嘗試
        }
    }
}

效果圖展示

在這里插入圖片描述

在這里插入圖片描述

這里設置的鎖過期是5秒每隔2/3的時間也就是4秒進行一次續(xù)期一共續(xù)了3次,因為我中間讓線程睡了12秒??梢钥吹芥i被正常續(xù)費了,確保了業(yè)務的正常執(zhí)行不會搶占資源。

到此這篇關于spring-data-redis自定義實現看門狗機制的文章就介紹到這了,更多相關spring-data-redis 看門狗內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Spring的@Transactional注解使用詳細解析

    Spring的@Transactional注解使用詳細解析

    這篇文章主要介紹了Spring的@Transactional注解使用詳細解析,@Transactional 注解相信大家并不陌生,平時開發(fā)中很常用的一個注解,它能保證方法內多個數據庫操作要么同時成功、要么同時失敗,需要的朋友可以參考下
    2023-11-11
  • 分析那些不講武德的SDK(構造使用規(guī)范)

    分析那些不講武德的SDK(構造使用規(guī)范)

    這篇文章主要為大家介紹了盤點分析那些不講武德的SDK(構造規(guī)范)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • Token安全存儲的幾種方式小結

    Token安全存儲的幾種方式小結

    在現代 Web 應用中,身份認證與授權是確保系統(tǒng)安全性的重要部分,Token被廣泛應用,作為實現身份認證的主要方式,然而,如何安全地存儲這些 Token,是每個開發(fā)者在構建前端應用時必須考慮的問題,本文將深入探討Token安全存儲的幾種方式,需要的朋友可以參考下
    2025-04-04
  • 純Java實現數字證書生成簽名的簡單實例

    純Java實現數字證書生成簽名的簡單實例

    下面小編就為大家?guī)硪黄僇ava實現數字證書生成簽名的簡單實例。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • Java實現的猴子吃桃問題算法示例

    Java實現的猴子吃桃問題算法示例

    這篇文章主要介紹了Java實現的猴子吃桃問題算法,簡單描述了猴子吃桃問題并結合實例形式給出了java解決猴子吃桃問題的具體實現技巧,需要的朋友可以參考下
    2017-10-10
  • java中的switch case語句使用詳解

    java中的switch case語句使用詳解

    這篇文章主要介紹了java中的switch case語句使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • 遠程debug調試入門

    遠程debug調試入門

    這篇文章主要介紹了Eclipse的Debug調試技巧大全(總結),小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧嗎,希望能給你帶來幫助
    2021-06-06
  • SpringBoot lombok(注解@Getter @Setter)詳解

    SpringBoot lombok(注解@Getter @Setter)詳解

    通過使用Lombok庫,SpringBoot應用可以自動化生成常用的方法如setter和getter,顯著降低了代碼冗余并提高了開發(fā)效率,Lombok的@Getter和@Setter注解用于自動生成屬性的訪問和修改方法,而@Data注解則提供了一個全面的解決方案
    2024-11-11
  • 通過Java實現獲取表的自增主鍵值

    通過Java實現獲取表的自增主鍵值

    這篇文章主要為大家詳細介紹了如何通過Java實現獲取表的自增主鍵值,文中的示例代碼講解詳細,具有一定的學習價值,感興趣的可以了解一下
    2023-06-06
  • spring?kafka?@KafkaListener詳解與使用過程

    spring?kafka?@KafkaListener詳解與使用過程

    這篇文章主要介紹了spring-kafka?@KafkaListener詳解與使用,本文結合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-02-02

最新評論

正阳县| 陇南市| 张家川| 苍南县| 开封市| 海门市| 瓦房店市| 白河县| 称多县| 贡嘎县| 广河县| 察隅县| 息烽县| 渑池县| 东乌珠穆沁旗| 连州市| 兴和县| 蒙自县| 东兰县| 茌平县| 新宾| 昂仁县| 梅州市| 南丰县| 金寨县| 姚安县| 无极县| 湘潭市| 江城| 花垣县| 博乐市| 鄂伦春自治旗| 本溪| 庆安县| 长寿区| 辽宁省| 平舆县| 百色市| 青海省| 和平区| 阿荣旗|