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

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

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

背景

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

以目前的系統(tǒng)架構(gòu)來(lái)說(shuō),用戶的請(qǐng)求一般會(huì)先經(jīng)過(guò)緩存系統(tǒng),如果緩存中沒有相關(guān)的數(shù)據(jù),就會(huì)在其他系統(tǒng)中查詢到相應(yīng)的數(shù)據(jù)并保存在緩存中,最后返回給調(diào)用方。

本地緩存:指程序級(jí)別的緩存組件,它的特點(diǎn)是本地緩存和應(yīng)用程序會(huì)運(yùn)行在同一個(gè)進(jìn)程中,所以本地緩存的操作會(huì)非常快,因?yàn)樵谕粋€(gè)進(jìn)程內(nèi)也意味著不會(huì)有網(wǎng)絡(luò)上的延遲和開銷。

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

除此之外,無(wú)法共享緩存可能會(huì)造成系統(tǒng)資源的浪費(fèi),這是因?yàn)槊總€(gè)系統(tǒng)都單獨(dú)維護(hù)了一份屬于自己的緩存,而同一份緩存有可能被多個(gè)系統(tǒng)單獨(dú)進(jìn)行存儲(chǔ),從而浪費(fèi)了系統(tǒng)資源。

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

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

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

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

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

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

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

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

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

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

緩存雪崩

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

解決方案:

  • 請(qǐng)求加鎖:對(duì)于并發(fā)量不是很多的應(yīng)用,使用請(qǐng)求加鎖排隊(duì)的方案 防止過(guò)多請(qǐng)求數(shù)據(jù)庫(kù)。
  • 失效更新:為每一個(gè)緩存數(shù)據(jù)都增加過(guò)期標(biāo)記來(lái)記錄緩存數(shù)據(jù)是否 失效,如果緩存標(biāo)記失效,則更新數(shù)據(jù)緩存。
  • 緩存數(shù)據(jù)的過(guò)期時(shí)間設(shè)置隨機(jī):為不同的數(shù)據(jù)設(shè)置不同的緩存失效時(shí)間,防止在同一時(shí)刻有大量的數(shù)據(jù)失效。
  • 如果緩存數(shù)據(jù)庫(kù)是分布式部署,將熱點(diǎn)數(shù)據(jù)均勻分布在不同的緩存數(shù)據(jù)庫(kù)中。
  • 設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過(guò)期。

緩存穿透

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

解決方案:

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

緩存擊穿

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

解決方案:

  • 設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過(guò)期。
  • 加互斥鎖。

緩存降級(jí)

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

服務(wù)降級(jí)策略:

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

一、在pom中添加依賴

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

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

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

三、編寫Redis配置文件

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    
    /**
     * RedisTemplate相關(guān)配置
     * 使redis支持插入對(duì)象
     *
     * @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值(默認(rèn)使用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等會(huì)跑出異常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSerializer.setObjectMapper(om);
        
        // 值采用json序列化
        template.setValueSerializer(jacksonSerializer);
        
        // 使用StringRedisSerializer來(lái)序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        
        // 設(shè)置hash key 和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

四、測(cè)試Redis緩存

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

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

    /**
     * 測(cè)試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);
    }

    /**
     * 測(cè)試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);
    }


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

}

4.1 測(cè)試key、value 為string

4.1.1 使用接口往redis添加記錄

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

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

4.2 測(cè)試key為string,value 為對(duì)象

五、工具類

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

/**
 * @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;
    }

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

    /**
     * 指定緩存失效時(shí)間
     *
     * @param key  鍵
     * @param time 時(shí)間(秒)
     * @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 獲取過(guò)期時(shí)間
     *
     * @param key 鍵 不能為null
     * @return 時(shí)間(秒) 返回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 可以傳一個(gè)值 或多個(gè)
     */
    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的消息隊(duì)列
     *
     * @param channel
     * @param message 消息內(nèi)容
     */
    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;
        }
    }

    /**
     * 普通緩存放入并設(shè)置時(shí)間
     *
     * @param key   鍵
     * @param value 值
     * @param time  時(shí)間(秒) time要大于0 如果time小于等于0 將設(shè)置無(wú)限期
     * @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  項(xiàng)
     * @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  項(xiàng)
     * @param value 值
     * @param time  時(shí)間(秒)  注意:如果已存在的hash表有時(shí)間,這里將會(huì)替換原有的時(shí)間
     * @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 項(xiàng) 不能為null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

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

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

    /**
     * HashSet
     *
     * @param key 鍵
     * @param map 對(duì)應(yīng)多個(gè)鍵值
     * @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 并設(shè)置時(shí)間
     *
     * @param key  鍵
     * @param map  對(duì)應(yīng)多個(gè)鍵值
     * @param time 時(shí)間(秒)
     * @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表中是否有該項(xiàng)的值
     *
     * @param key  鍵 不能為null
     * @param item 項(xiàng) 不能為null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash遞增 如果不存在,就會(huì)創(chuàng)建一個(gè) 并把新增后的值返回
     *
     * @param key  鍵
     * @param item 項(xiàng)
     * @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 項(xiàng)
     * @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從一個(gè)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 值 可以是多個(gè)
     * @return 成功個(gè)數(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   時(shí)間(秒)
     * @param values 值 可以是多個(gè)
     * @return 成功個(gè)數(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緩存的長(zhǎng)度
     *
     * @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 值 可以是多個(gè)
     * @return 移除的個(gè)數(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緩存的內(nèi)容
     *
     * @param key   鍵
     * @param start 開始
     * @param end   結(jié)束  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緩存的長(zhǎng)度
     *
     * @param key 鍵
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通過(guò)索引 獲取list中的值
     *
     * @param key   鍵
     * @param index 索引  index>=0時(shí), 0 表頭,1 第二個(gè)元素,依次類推;index<0時(shí),-1,表尾,-2倒數(shù)第二個(gè)元素,依次類推
     * @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  時(shí)間(秒)
     * @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  時(shí)間(秒)
     * @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個(gè)值為value
     *
     * @param key   鍵
     * @param count 移除多少個(gè)
     * @param value 值
     * @return 移除的個(gè)數(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

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

相關(guān)文章

  • Java靜態(tài)代理和動(dòng)態(tài)代理總結(jié)

    Java靜態(tài)代理和動(dòng)態(tài)代理總結(jié)

    這篇文章主要介紹了Java靜態(tài)代理和動(dòng)態(tài)代理總結(jié),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • Spring組件初始化擴(kuò)展點(diǎn)BeanPostProcessor的作用詳解

    Spring組件初始化擴(kuò)展點(diǎn)BeanPostProcessor的作用詳解

    本文通過(guò)實(shí)戰(zhàn)案例和常見應(yīng)用場(chǎng)景詳細(xì)介紹了BeanPostProcessor的使用,并強(qiáng)調(diào)了其在Spring擴(kuò)展中的重要性,感興趣的朋友一起看看吧
    2025-03-03
  • 最新評(píng)論