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

SpringBoot+Redis實現(xiàn)分布式緩存的方法步驟

 更新時間:2024年07月12日 10:01:29   作者:憂傷夏天的風  
在高并發(fā)的分布式的系統(tǒng)中,緩存是提升系統(tǒng)性能的重要手段,本文主要介紹了SpringBoot+Redis實現(xiàn)分布式緩存的方法步驟,具有一定的參考價值,感興趣的可以了解一下

背景

緩存(Cache):指將程序或系統(tǒng)中常用的數(shù)據(jù)對象存儲在像內存這樣特定的介質中,以避免在每次程序調用時,重新創(chuàng)建或組織數(shù)據(jù)所帶來的性能損耗,從而提高了系統(tǒng)的整體運行速度。

以目前的系統(tǒng)架構來說,用戶的請求一般會先經(jīng)過緩存系統(tǒng),如果緩存中沒有相關的數(shù)據(jù),就會在其他系統(tǒng)中查詢到相應的數(shù)據(jù)并保存在緩存中,最后返回給調用方。

本地緩存:指程序級別的緩存組件,它的特點是本地緩存和應用程序會運行在同一個進程中,所以本地緩存的操作會非常快,因為在同一個進程內也意味著不會有網(wǎng)絡上的延遲和開銷。

本地緩存適用于單節(jié)點非集群的應用場景,它的優(yōu)點是快,缺點是多程序無法共享緩存,比如分布式用戶 Session 會話信息保存,由于每次用戶訪問的服務器可能是不同的,如果不能共享緩存,那么就意味著每次的請求操作都有可能被系統(tǒng)阻止,因為會話信息只保存在某一個服務器上,當請求沒有被轉發(fā)到這臺存儲了用戶信息的服務器時,就會被認為是非登錄的違規(guī)操作。

除此之外,無法共享緩存可能會造成系統(tǒng)資源的浪費,這是因為每個系統(tǒng)都單獨維護了一份屬于自己的緩存,而同一份緩存有可能被多個系統(tǒng)單獨進行存儲,從而浪費了系統(tǒng)資源。

分布式緩存:指將應用系統(tǒng)和緩存組件進行分離的緩存機制,這樣多個應用系統(tǒng)就可以共享一套緩存數(shù)據(jù)了,它的特點是共享緩存服務和可集群部署,為緩存系統(tǒng)提供了高可用的運行環(huán)境,以及緩存共享的程序運行機制。

本地緩存可以使用EhCache 和 Google 的 Guava來實現(xiàn),而分布式緩存可以使用 Redis 或 Memcached 來實現(xiàn)。

由于 Redis 本身就是獨立的緩存系統(tǒng),因此可以作為第三方來提供共享的數(shù)據(jù)緩存,而 Redis 的分布式支持主從、哨兵和集群的模式,所以它就可以支持分布式的緩存,而 Memcached 的情況也是類似的。

分布式緩存常見文件及解決方案

分布式緩存設計的核心問題是以哪種方式進行緩存預熱和緩存更新, 以及如何優(yōu)雅解決緩存雪崩、緩存穿透、緩存降級等問題。這些問題在不 同的應用場景下有不同的解決方案。

緩存預熱: 緩存預熱指在用戶請求數(shù)據(jù)前先將數(shù)據(jù)加載到緩存系統(tǒng)中,用戶查詢 事先被預熱的緩存數(shù)據(jù),以提高系統(tǒng)查詢效率。緩存預熱一般有系統(tǒng)啟動 加載、定時加載等方式。

緩存更新: 緩存更新指在數(shù)據(jù)發(fā)生變化后及時將變化后的數(shù)據(jù)更新到緩存中。常 見的緩存更新策略有以下4種。

  •  定時更新:定時將底層數(shù)據(jù)庫內的數(shù)據(jù)更新到緩存中,該方法比較 簡單,適合需要緩存的數(shù)據(jù)量不是很大的應用場景。
  • 過期更新:定時將緩存中過期的數(shù)據(jù)更新為最新數(shù)據(jù)并更新緩存的 過期時間。
  • 寫請求更新:在用戶有寫請求時先寫數(shù)據(jù)庫同時更新緩存,這適用 于用戶對緩存數(shù)據(jù)和數(shù)據(jù)庫的數(shù)據(jù)有實時強一致性要求的情況。
  •  讀請求更新:在用戶有讀請求時,先判斷該請求數(shù)據(jù)的緩存是否存 在或過期,如果不存在或已過期,則進行底層數(shù)據(jù)庫查詢并將查詢結果更 新到緩存中,同時將查詢結果返回給用戶。

緩存淘汰策略 在緩存數(shù)據(jù)過多時需要使用某種淘汰算法決定淘汰哪些數(shù)據(jù)。常用的 淘汰算法有以下幾種。

  •  FIFO(First In First Out,先進先出):判斷被存儲的時間,離 目前最遠的數(shù)據(jù)優(yōu)先被淘汰。
  •  LRU(Least Recently Used,最近最少使用):判斷緩存最近被使 用的時間,距離當前時間最遠的數(shù)據(jù)優(yōu)先被淘汰。
  •  LFU(Least Frequently Used,最不經(jīng)常使用):在一段時間內, 被使用次數(shù)最少的緩存優(yōu)先被淘汰。

緩存雪崩

緩存雪崩指在同一時刻由于大量緩存失效,導致大量原本應該訪問緩 存的請求都去查詢數(shù)據(jù)庫,而對數(shù)據(jù)庫的CPU和內存造成巨大壓力,嚴重的 話會導致數(shù)據(jù)庫宕機,從而形成一系列連鎖反應,使整個系統(tǒng)崩潰。

解決方案:

  • 請求加鎖:對于并發(fā)量不是很多的應用,使用請求加鎖排隊的方案 防止過多請求數(shù)據(jù)庫。
  • 失效更新:為每一個緩存數(shù)據(jù)都增加過期標記來記錄緩存數(shù)據(jù)是否 失效,如果緩存標記失效,則更新數(shù)據(jù)緩存。
  • 緩存數(shù)據(jù)的過期時間設置隨機:為不同的數(shù)據(jù)設置不同的緩存失效時間,防止在同一時刻有大量的數(shù)據(jù)失效。
  • 如果緩存數(shù)據(jù)庫是分布式部署,將熱點數(shù)據(jù)均勻分布在不同的緩存數(shù)據(jù)庫中。
  • 設置熱點數(shù)據(jù)永遠不過期。

緩存穿透

緩存穿透指由于緩存系統(tǒng)故障或者用戶頻繁查詢系統(tǒng)中不存在(在系 統(tǒng)中不存在,在自然數(shù)據(jù)庫和緩存中都不存在)的數(shù)據(jù),而這時請求穿過 緩存不斷被發(fā)送到數(shù)據(jù)庫,導致數(shù)據(jù)庫過載,進而引發(fā)一連串并發(fā)問題。 比如用戶發(fā)起一個userName為zhangsan的請求,而在系統(tǒng)中并沒有名 為zhangsan的用戶,這樣就導致每次查詢時在緩存中都找不到該數(shù)據(jù),然 后去數(shù)據(jù)庫中再查詢一遍。由于zhangsan用戶本身在系統(tǒng)中不存在,自然 返回空,導致請求穿過緩存頻繁查詢數(shù)據(jù)庫,在用戶頻繁發(fā)送該請求時將 導致數(shù)據(jù)庫系統(tǒng)負載增大,從而可能引發(fā)其他問題。常用的解決緩存穿透 問題的方法有布隆過濾器和cache null策略。

解決方案:

  • 接口層增加校驗,如用戶鑒權校驗,id做基礎校驗,id<=0的直接攔截,一定不存在的不去查詢數(shù)據(jù)庫。
  • 布隆過濾器:指將所有可能存在的數(shù)據(jù)都映射到一個足夠大的 Bitmap中,在用戶發(fā)起請求時首先經(jīng)過布隆過濾器的攔截,一個一定不存 在的數(shù)據(jù)會被這個布隆過濾器攔截,從而避免對底層存儲系統(tǒng)帶來查詢上 的壓力。
  • cache null策略:指如果一個查詢返回的結果為null(可能是數(shù)據(jù) 不存在,也可能是系統(tǒng)故障),我們仍然緩存這個null結果,但它的過期 時間會很短,通常不超過 5 分鐘;在用戶再次請求該數(shù)據(jù)時直接返回 null,而不會繼續(xù)訪問數(shù)據(jù)庫,從而有效保障數(shù)據(jù)庫的安全。其實cache null策略的核心原理是:在緩存中記錄一個短暫的(數(shù)據(jù)過期時間內)數(shù) 據(jù)在系統(tǒng)中是否存在的狀態(tài),如果不存在,則直接返回null,不再查詢數(shù) 據(jù)庫,從而避免緩存穿透到數(shù)據(jù)庫上。

緩存擊穿

緩存擊穿是指緩存中沒有但數(shù)據(jù)庫中有的數(shù)據(jù)(一般是緩存時間到期),這時由于并發(fā)用戶特別多,同時讀緩存沒讀到數(shù)據(jù),又同時去數(shù)據(jù)庫去取數(shù)據(jù),引起數(shù)據(jù)庫壓力瞬間增大,造成過大壓力

解決方案:

  • 設置熱點數(shù)據(jù)永遠不過期。
  • 加互斥鎖。

緩存降級

緩存降級指由于訪問量劇增導致服務出現(xiàn)問題(如響應時間慢或不響 應)時,優(yōu)先保障核心業(yè)務的運行,減少或關閉非核心業(yè)務對資源的使 用。

服務降級策略:

  • 寫降級:在寫請求增大時,可以只進行Cache的更新,然后將數(shù)據(jù) 異步更新到數(shù)據(jù)庫中,保證最終一致性即可,即將寫請求從數(shù)據(jù)庫降級為 Cache。
  • 讀降級:在數(shù)據(jù)庫服務負載過高或數(shù)據(jù)庫系統(tǒng)故障時,可以只對 Cache進行讀取并將結果返回給用戶,在數(shù)據(jù)庫服務正常后再去查詢數(shù)據(jù) 庫,即將讀請求從數(shù)據(jù)庫降級為Cache。這種方式適用于對數(shù)據(jù)實時性要求 不高的場景,保障了在系統(tǒng)發(fā)生故障的情況下用戶依然能夠訪問到數(shù)據(jù), 只是訪問到的數(shù)據(jù)相對有延遲。

一、在pom中添加依賴

<!--springboot redis依賴-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

二、在配置文件中配置Redis連接

# Redis數(shù)據(jù)庫索引(默認為0)
spring.redis.database=0
# Redis服務器地址
spring.redis.host=127.0.0.1
# Redis服務器連接端口
spring.redis.port=6379
# Redis服務器連接密碼(默認為空)
spring.redis.password=123456
# 連接池最大連接數(shù)(使用負值表示沒有限制)
spring.redis.jedis.pool.max-idle=10
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.jedis.pool.max-wait=3000
# 連接池中的最小空閑連接
spring.redis.jedis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=3000

三、編寫Redis配置文件

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    
    /**
     * RedisTemplate相關配置
     * 使redis支持插入對象
     *
     * @param factory
     * @return 方法緩存 Methods the cache
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置連接工廠
        template.setConnectionFactory(factory);
        // 序列化和反序列化redis的value值(默認使用JDK的序列化方式)
        Jackson2JsonRedisSerializer jacksonSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修飾符范圍,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化輸入的類型,類必須是非final修飾的,final修飾的類,比如String,Integer等會跑出異常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSerializer.setObjectMapper(om);
        
        // 值采用json序列化
        template.setValueSerializer(jacksonSerializer);
        
        // 使用StringRedisSerializer來序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        
        // 設置hash key 和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

四、測試Redis緩存

/**
 * @Author: oyc
 * @Description: redis 測試控制類
 * @Since 2020年5月12日 23:35:05
 */
@RestController
@RequestMapping("/redis")
public class OyRedisController {

    /**
     * 依賴注入,注入redisTemplate
     */
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 測試redis string add
     */
    @GetMapping("/string/add")
    public String addStringKeyValue(@RequestParam(value = "key", defaultValue = "key1") String key, @RequestParam(value = "value", defaultValue = "redis value") String value) {
        redisTemplate.opsForValue().set(key, value);
        return (String) redisTemplate.opsForValue().get(key);
    }

    /**
     * 測試redis string add
     */
    @GetMapping("/object/add")
    public Object addObjectKeyValue(@RequestParam(value = "key", defaultValue = "key1") String key) {
        OyUser user = new OyUser(1, "宋江", "18", "male");
        redisTemplate.opsForValue().set(key, user);
        return redisTemplate.opsForValue().get(key);
    }


    /**
     * 測試redis string get
     */
    @GetMapping("/string/get")
    public Object getStringByKey(@RequestParam(value = "key", defaultValue = "key1") String key) {
        return redisTemplate.opsForValue().get(key);
    }

}

4.1 測試key、value 為string

4.1.1 使用接口往redis添加記錄

4.1.2 使用IDEA的redis客戶端插件查看記錄: 

4.1.3 使用接口獲取緩存數(shù)據(jù):

4.2 測試key為string,value 為對象

五、工具類

上面案例都是直接用RedisTemplate操作Redis,操作比較復雜,借鑒網(wǎng)友寫了一個RedisUtils工具類,RedisUtils交給Spring容器實例化,使用時直接注解注入,使用方便簡單,減少使用難度。

/**
 * @Description: redisTemplate封裝
 * Redis支持五種數(shù)據(jù)類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
 * @Author: oyc
 * @Since 2020年5月12日 23:41:08
 */
@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    //==========================基本操作===============================

    /**
     * 指定緩存失效時間
     *
     * @param key  鍵
     * @param time 時間(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根據(jù)key 獲取過期時間
     *
     * @param key 鍵 不能為null
     * @return 時間(秒) 返回0代表為永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判斷key是否存在
     *
     * @param key 鍵
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 刪除緩存
     *
     * @param key 可以傳一個值 或多個
     */
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    /**
     * 模糊查詢獲取key值
     *
     * @param pattern
     * @return
     */
    public Set keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 使用Redis的消息隊列
     *
     * @param channel
     * @param message 消息內容
     */
    public void convertAndSend(String channel, Object message) {
        redisTemplate.convertAndSend(channel, message);
    }

    //============================String=============================

    /**
     * 普通緩存獲取
     *
     * @param key 鍵
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通緩存放入
     *
     * @param key   鍵
     * @param value 值
     * @return true成功 false失敗
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通緩存放入并設置時間
     *
     * @param key   鍵
     * @param value 值
     * @param time  時間(秒) time要大于0 如果time小于等于0 將設置無限期
     * @return true成功 false 失敗
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 遞增
     *
     * @param key   鍵
     * @param delta 要增加幾(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("遞增因子必須大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 遞減
     *
     * @param key   鍵
     * @param delta 要減少幾(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("遞減因子必須大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    //================================hash=================================

    /**
     * 向一張hash表中放入數(shù)據(jù),如果不存在將創(chuàng)建
     *
     * @param key   鍵
     * @param item  項
     * @param value 值
     * @return true 成功 false失敗
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一張hash表中放入數(shù)據(jù),如果不存在將創(chuàng)建
     *
     * @param key   鍵
     * @param item  項
     * @param value 值
     * @param time  時間(秒)  注意:如果已存在的hash表有時間,這里將會替換原有的時間
     * @return true 成功 false失敗
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashGet
     *
     * @param key  鍵 不能為null
     * @param item 項 不能為null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 刪除hash表中的值
     *
     * @param key  鍵 不能為null
     * @param item 項 可以使多個 不能為null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 獲取hashKey對應的所有鍵值
     *
     * @param key 鍵
     * @return 對應的多個鍵值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     *
     * @param key 鍵
     * @param map 對應多個鍵值
     * @return true 成功 false 失敗
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 并設置時間
     *
     * @param key  鍵
     * @param map  對應多個鍵值
     * @param time 時間(秒)
     * @return true成功 false失敗
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 判斷hash表中是否有該項的值
     *
     * @param key  鍵 不能為null
     * @param item 項 不能為null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash遞增 如果不存在,就會創(chuàng)建一個 并把新增后的值返回
     *
     * @param key  鍵
     * @param item 項
     * @param by   要增加幾(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash遞減
     *
     * @param key  鍵
     * @param item 項
     * @param by   要減少記(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }


    //============================set=============================
    /**
     * 根據(jù)key獲取Set中的所有值
     *
     * @param key 鍵
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根據(jù)value從一個set中查詢,是否存在
     *
     * @param key   鍵
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將數(shù)據(jù)放入set緩存
     *
     * @param key    鍵
     * @param values 值 可以是多個
     * @return 成功個數(shù)
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 將set數(shù)據(jù)放入緩存
     *
     * @param key    鍵
     * @param time   時間(秒)
     * @param values 值 可以是多個
     * @return 成功個數(shù)
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 獲取set緩存的長度
     *
     * @param key 鍵
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值為value的
     *
     * @param key    鍵
     * @param values 值 可以是多個
     * @return 移除的個數(shù)
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    //===============================list=================================
    /**
     * 獲取list緩存的內容
     *
     * @param key   鍵
     * @param start 開始
     * @param end   結束  0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 獲取list緩存的長度
     *
     * @param key 鍵
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通過索引 獲取list中的值
     *
     * @param key   鍵
     * @param index 索引  index>=0時, 0 表頭,1 第二個元素,依次類推;index<0時,-1,表尾,-2倒數(shù)第二個元素,依次類推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 將list放入緩存
     *
     * @param key   鍵
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入緩存
     *
     * @param key   鍵
     * @param value 值
     * @param time  時間(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入緩存
     *
     * @param key   鍵
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入緩存
     *
     * @param key   鍵
     * @param value 值
     * @param time  時間(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根據(jù)索引修改list中的某條數(shù)據(jù)
     *
     * @param key   鍵
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N個值為value
     *
     * @param key   鍵
     * @param count 移除多少個
     * @param value 值
     * @return 移除的個數(shù)
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

源碼: https://github.com/oycyqr/springboot-learning-demo/tree/master/springboot-redis

到此這篇關于SpringBoot+Redis 實現(xiàn)分布式緩存的方法步驟的文章就介紹到這了,更多相關SpringBoot Redis 分布式緩存內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • ThreadPoolExecutor中的submit()方法詳細講解

    ThreadPoolExecutor中的submit()方法詳細講解

    在使用線程池的時候,發(fā)現(xiàn)除了execute()方法可以執(zhí)行任務外,還發(fā)現(xiàn)有一個方法submit()可以執(zhí)行任務,本文就詳細的介紹一下ThreadPoolExecutor中的submit()方法,具有一定的參考價值,感興趣的可以了解一下
    2022-04-04
  • CORS跨域問題常用解決方法代碼實例

    CORS跨域問題常用解決方法代碼實例

    這篇文章主要介紹了CORS跨域問題常用解決方法代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • Spring中@Scope注解用法解析

    Spring中@Scope注解用法解析

    這篇文章主要介紹了Spring中@Scope注解用法解析,@Scope注解主要作用是調節(jié)Ioc容器中的作用域,在Spring IoC容器中主要有以下五種作用域,需要的朋友可以參考下
    2023-11-11
  • java.net.SocketTimeoutException: Read timed out異常的解決

    java.net.SocketTimeoutException: Read timed o

    本文主要介紹了java.net.SocketTimeoutException: Read timed out異常的解決,可能是因為網(wǎng)絡延遲、服務器響應慢或連接不穩(wěn)定等原因造成的,下面就一起來介紹一下,感興趣的可以了解一下
    2024-05-05
  • 初探Java內部類的使用

    初探Java內部類的使用

    Java內部類一般可以分為以下三種:成員內部類、靜態(tài)內部類和匿名內部類。這篇文章主要帶大家初探一下Java內部類的使用,感興趣的可以了解一下
    2022-09-09
  • Java RabbitMQ 中的消息長期不消費會過期嗎

    Java RabbitMQ 中的消息長期不消費會過期嗎

    RabbitMQ支持消息的過期時間,在消息發(fā)送時可以進行指定。 RabbitMQ支持隊列的過期時間,從消息入隊列開始計算,只要超過了隊列的超時時間配置,那么消息會自動的清除
    2021-09-09
  • Java 實現(xiàn)加密數(shù)據(jù)庫連接的步驟

    Java 實現(xiàn)加密數(shù)據(jù)庫連接的步驟

    這篇文章主要介紹了Java 實現(xiàn)加密數(shù)據(jù)庫連接的步驟,幫助大家更好的理解和使用Java處理數(shù)據(jù)庫,感興趣的朋友可以了解下
    2020-11-11
  • SpringBoot中Starter的作用小結

    SpringBoot中Starter的作用小結

    這篇文章主要介紹了SpringBoot中Starter的作用小結,Starter其實就是Spring針對不用的開發(fā)場景,給我們提供的“套餐”。今天就通過實例代碼給大家介紹Starter,感興趣的朋友一起看看吧
    2021-10-10
  • 智能手表開發(fā)API接口

    智能手表開發(fā)API接口

    這篇文章主要介紹了智能手表開發(fā)API接口,使用圖靈機器人平臺接口實現(xiàn)天氣預報,非常簡單實用,這里推薦給大家。
    2015-03-03
  • Druid基本配置及內置監(jiān)控使用_動力節(jié)點Java學院整理

    Druid基本配置及內置監(jiān)控使用_動力節(jié)點Java學院整理

    這篇文章主要介紹了Druid基本配置及內置監(jiān)控使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08

最新評論