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

Redis緩存工具封裝實(shí)現(xiàn)

 更新時(shí)間:2023年01月15日 11:02:01   作者:嗯mua.  
本文主要介紹了Redis緩存工具封裝實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

將 StringRedisTemplate 封裝成一個(gè)緩存工具類,方便以后重復(fù)使用。

1. 方法要求

在這個(gè)工具類中我們完成四個(gè)方法:

  • 方法①:將任意Java對(duì)象序列化為json并存儲(chǔ)在string類型的key中,并且可以設(shè)置TTL過期時(shí)間
  • 方法②:將任意Java對(duì)象序列化為json并存儲(chǔ)在string類型的key中,并且可以設(shè)置邏輯過期時(shí)間,用于處理緩存擊穿問題
  • 方法③:根據(jù)指定的key查詢緩存,并反序列化為指定類型,利用緩存空值的方式解決緩存穿透問題
  • 方法④:根據(jù)指定的key查詢緩存,并反序列化為指定類型,需要利用邏輯過期解決緩存擊穿問題

我們新建一個(gè)類,先把大致框架寫出來,方法的參數(shù)可以邊寫邊完善,但是我的方法參數(shù)已經(jīng)完善好了:

@Component
public class CacheClient {

? ? private final StringRedisTemplate stringRedisTemplate;

? ? public CacheClient(StringRedisTemplate stringRedisTemplate) {
? ? ? ? this.stringRedisTemplate = stringRedisTemplate;
? ? }

? ? //方法一
? ? public void set(String key, Object value, Long time, TimeUnit unit) {
? ? }

? ? //方法二
? ? public void setWithLogicExpire(String key, Object value, Long time, TimeUnit unit) {
? ? }

? ? //方法三
? ? public <R, ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Long time, TimeUnit unit, Function<ID, R> dbFallback) {
? ? }

? ? //方法四
? ? public <R, ID> R queryWithLogicalExpire(String prefix, ID id, String lockPre, Class<R> type,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Long time, TimeUnit unit, Function<ID, R> dbFallback) {
? ? }

? ? //線程池
? ? private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);

? ? //獲取鎖
? ? private boolean tryLock(String key) {
? ? ? ? Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", LOCK_SHOP_TTL, TimeUnit.SECONDS);
? ? ? ? return BooleanUtil.isTrue(flag);
? ? }

? ? //釋放鎖
? ? private void unLock(String key) {
? ? ? ? stringRedisTemplate.delete(key);
? ? }
}

接下來我們可以不斷完善這些方法。

1.1 方法一

public void set(String key, Object value, Long time, TimeUnit unit) {
? ? stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, unit);
}

1.2 方法二

public void setWithLogicExpire(String key, Object value, Long time, TimeUnit unit) {
? ? RedisData redisData = new RedisData();
? ? redisData.setData(value);
? ? redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
? ? stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
}

1.3 方法三

public <R, ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type,
                                          Long time, TimeUnit unit, Function<ID, R> dbFallback) {
    String key = keyPrefix + id;
    //1.從redis中查詢商鋪緩存
    String json = stringRedisTemplate.opsForValue().get(key);
    //2.判斷是否存在
    if (StrUtil.isNotBlank(json)) {
        //2.1.存在
        return JSONUtil.toBean(json, type);
    }
    //2.2.不存在
    //判斷是否為空值
    if (json != null) {
        //不為null,則必為空
        return null;
    }
    //3.查詢數(shù)據(jù)庫
    R r = dbFallback.apply(id);
    if (r == null) {
        //3.1.不存在,緩存空值
        stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);
    } else {
        //3.2.存在,緩存數(shù)據(jù)
        this.set(key, r, time, unit);
    }
    return r;
}

方法三用到了函數(shù)式編程,這里非常巧妙,順便再貼一下調(diào)用方法是怎樣調(diào)用的:

Shop shop = cacheClient.queryWithPassThrough(CACHE_SHOP_KEY,id,Shop.class,CACHE_SHOP_TTL,TimeUnit.MINUTES,this::getById);

1.4 方法四

public <R, ID> R queryWithLogicalExpire(String prefix, ID id, String lockPre, Class<R> type,
                                            Long time, TimeUnit unit, Function<ID, R> dbFallback) {
    //1.從redis查詢商鋪緩存
    String key = prefix + id;
    String json = stringRedisTemplate.opsForValue().get(key);
    //2.判斷是否存在
    if (StrUtil.isBlank(json)) {
        //未命中,直接返回空
        return null;
    }
    //3.命中,判斷是否過期
    RedisData redisData = JSONUtil.toBean(json, RedisData.class);
    R r = JSONUtil.toBean((JSONObject) redisData.getData(), type);
    if (redisData.getExpireTime().isAfter(LocalDateTime.now())) {
        //3.1未過期,直接返回店鋪信息
        return r;
    }
    //3.2.已過期,緩存重建
    //3.3.獲取鎖
    String lockKey = lockPre + id;
    boolean flag = tryLock(lockKey);
    if (flag) {
        //3.4.獲取成功
        //4再次檢查redis緩存是否過期,做double check
        json = stringRedisTemplate.opsForValue().get(key);
        //4.1.判斷是否存在
        if (StrUtil.isBlank(json)) {
            //未命中,直接返回空
            return null;
        }
        //4.2.命中,判斷是否過期
        redisData = JSONUtil.toBean(json, RedisData.class);
        r = JSONUtil.toBean((JSONObject) redisData.getData(), type);
        if (redisData.getExpireTime().isAfter(LocalDateTime.now())) {
            //4.3.未過期,直接返回店鋪信息
            return r;
        }
        //4.4過期,返回舊數(shù)據(jù)
        CACHE_REBUILD_EXECUTOR.submit(() -> {
            //5.重建緩存
            try {
                R r1 = dbFallback.apply(id);
                this.setWithLogicExpire(key, r1, time, unit);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                //釋放鎖
                unLock(lockKey);
            }
        });
    }
    //7.獲取失敗,返回舊數(shù)據(jù)
    return r;
}

2. 完整工具類代碼

@Component
@Slf4j
public class CacheClient {

? ? private final StringRedisTemplate stringRedisTemplate;

? ? public CacheClient(StringRedisTemplate stringRedisTemplate) {
? ? ? ? this.stringRedisTemplate = stringRedisTemplate;
? ? }

? ? public void set(String key, Object value, Long time, TimeUnit unit) {
? ? ? ? stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, unit);
? ? }

? ? public void setWithLogicExpire(String key, Object value, Long time, TimeUnit unit) {
? ? ? ? RedisData redisData = new RedisData();
? ? ? ? redisData.setData(value);
? ? ? ? redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
? ? ? ? stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
? ? }

? ? public <R, ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Long time, TimeUnit unit, Function<ID, R> dbFallback) {
? ? ? ? String key = keyPrefix + id;
? ? ? ? //1.從redis中查詢商鋪緩存
? ? ? ? String json = stringRedisTemplate.opsForValue().get(key);
? ? ? ? //2.判斷是否存在
? ? ? ? if (StrUtil.isNotBlank(json)) {
? ? ? ? ? ? //2.1.存在
? ? ? ? ? ? return JSONUtil.toBean(json, type);
? ? ? ? }
? ? ? ? //2.2.不存在
? ? ? ? //判斷是否為空值
? ? ? ? if (json != null) {
? ? ? ? ? ? //不為null,則必為空
? ? ? ? ? ? return null;
? ? ? ? }
? ? ? ? //3.查詢數(shù)據(jù)庫
? ? ? ? R r = dbFallback.apply(id);
? ? ? ? if (r == null) {
? ? ? ? ? ? //3.1.不存在,緩存空值
? ? ? ? ? ? stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);
? ? ? ? } else {
? ? ? ? ? ? //3.2.存在,緩存數(shù)據(jù)
? ? ? ? ? ? this.set(key, r, time, unit);
? ? ? ? }
? ? ? ? return r;
? ? }

? ? public <R, ID> R queryWithLogicalExpire(String prefix, ID id, String lockPre, Class<R> type,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Long time, TimeUnit unit, Function<ID, R> dbFallback) {
? ? ? ? //1.從redis查詢商鋪緩存
? ? ? ? String key = prefix + id;
? ? ? ? String json = stringRedisTemplate.opsForValue().get(key);
? ? ? ? //2.判斷是否存在
? ? ? ? if (StrUtil.isBlank(json)) {
? ? ? ? ? ? //未命中,直接返回空
? ? ? ? ? ? return null;
? ? ? ? }
? ? ? ? //3.命中,判斷是否過期
? ? ? ? RedisData redisData = JSONUtil.toBean(json, RedisData.class);
? ? ? ? R r = JSONUtil.toBean((JSONObject) redisData.getData(), type);
? ? ? ? if (redisData.getExpireTime().isAfter(LocalDateTime.now())) {
? ? ? ? ? ? //3.1未過期,直接返回店鋪信息
? ? ? ? ? ? return r;
? ? ? ? }
? ? ? ? //3.2.已過期,緩存重建
? ? ? ? //3.3.獲取鎖
? ? ? ? String lockKey = lockPre + id;
? ? ? ? boolean flag = tryLock(lockKey);
? ? ? ? if (flag) {
? ? ? ? ? ? //3.4.獲取成功
? ? ? ? ? ? //4再次檢查redis緩存是否過期,做double check
? ? ? ? ? ? json = stringRedisTemplate.opsForValue().get(key);
? ? ? ? ? ? //4.1.判斷是否存在
? ? ? ? ? ? if (StrUtil.isBlank(json)) {
? ? ? ? ? ? ? ? //未命中,直接返回空
? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? }
? ? ? ? ? ? //4.2.命中,判斷是否過期
? ? ? ? ? ? redisData = JSONUtil.toBean(json, RedisData.class);
? ? ? ? ? ? r = JSONUtil.toBean((JSONObject) redisData.getData(), type);
? ? ? ? ? ? if (redisData.getExpireTime().isAfter(LocalDateTime.now())) {
? ? ? ? ? ? ? ? //4.3.未過期,直接返回店鋪信息
? ? ? ? ? ? ? ? return r;
? ? ? ? ? ? }
? ? ? ? ? ? //4.4過期,返回舊數(shù)據(jù)
? ? ? ? ? ? CACHE_REBUILD_EXECUTOR.submit(() -> {
? ? ? ? ? ? ? ? //5.重建緩存
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? R r1 = dbFallback.apply(id);
? ? ? ? ? ? ? ? ? ? this.setWithLogicExpire(key, r1, time, unit);
? ? ? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? ? ? //釋放鎖
? ? ? ? ? ? ? ? ? ? unLock(lockKey);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? ? ? //7.獲取失敗,返回舊數(shù)據(jù)
? ? ? ? return r;
? ? }

? ? private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);

? ? //獲取鎖
? ? private boolean tryLock(String key) {
? ? ? ? Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", LOCK_SHOP_TTL, TimeUnit.SECONDS);
? ? ? ? return BooleanUtil.isTrue(flag);
? ? }

? ? //釋放鎖
? ? private void unLock(String key) {
? ? ? ? stringRedisTemplate.delete(key);
? ? }
}

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

相關(guān)文章

  • Redis特殊數(shù)據(jù)類型HyperLogLog基數(shù)統(tǒng)計(jì)算法講解

    Redis特殊數(shù)據(jù)類型HyperLogLog基數(shù)統(tǒng)計(jì)算法講解

    這篇文章主要為大家介紹了Redis特殊數(shù)據(jù)類型HyperLogLog基數(shù)統(tǒng)計(jì)算法講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Redis用GEO實(shí)現(xiàn)附近的人功能

    Redis用GEO實(shí)現(xiàn)附近的人功能

    GEO就是Geolocation的簡寫形式,代表地理坐標(biāo),這篇文章主要介紹了Redis用GEO實(shí)現(xiàn)附近的人功能,需要的朋友可以參考下
    2024-08-08
  • Redis 緩存實(shí)現(xiàn)存儲(chǔ)和讀取歷史搜索關(guān)鍵字的操作方法

    Redis 緩存實(shí)現(xiàn)存儲(chǔ)和讀取歷史搜索關(guān)鍵字的操作方法

    這篇文章主要介紹了Redis 緩存實(shí)現(xiàn)存儲(chǔ)和讀取歷史搜索關(guān)鍵字,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 從原理到實(shí)踐分析?Redis?分布式鎖的多種實(shí)現(xiàn)方案

    從原理到實(shí)踐分析?Redis?分布式鎖的多種實(shí)現(xiàn)方案

    在分布式系統(tǒng)中,為了保證多個(gè)進(jìn)程或線程之間的數(shù)據(jù)一致性和正確性,需要使用鎖來實(shí)現(xiàn)互斥訪問共享資源,然而,使用本地鎖在分布式系統(tǒng)中存在問題,這篇文章主要介紹了從原理到實(shí)踐分析?Redis?分布式鎖的多種實(shí)現(xiàn)方案,需要的朋友可以參考下
    2024-07-07
  • Redis命令處理過程源碼解析

    Redis命令處理過程源碼解析

    這篇文章主要介紹了Redis命令處理過程源碼解析,本文是基于社區(qū)版redis4.0.8,通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • python中使用redis用法詳解

    python中使用redis用法詳解

    Redis擁有豐富的數(shù)據(jù)結(jié)構(gòu),擁有事務(wù)功能,保證命令的原子性。由于是內(nèi)存數(shù)據(jù)庫,讀寫非常高速,可達(dá)10w/s的評(píng)率,所以一般應(yīng)用于數(shù)據(jù)變化快、實(shí)時(shí)通訊、緩存等。這篇文章給大家講解一下Python如何使用Redis,并進(jìn)行相關(guān)的實(shí)戰(zhàn)操作。
    2022-12-12
  • redis主從連接不成功錯(cuò)誤問題及解決

    redis主從連接不成功錯(cuò)誤問題及解決

    這篇文章主要介紹了redis主從連接不成功錯(cuò)誤問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教<BR>
    2024-01-01
  • Redis源碼閱讀:Redis字符串SDS詳解

    Redis源碼閱讀:Redis字符串SDS詳解

    這篇文章主要介紹了Redis源碼閱讀:Redis字符串SDS,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 使用lua+redis解決發(fā)多張券的并發(fā)問題

    使用lua+redis解決發(fā)多張券的并發(fā)問題

    這篇文章主要介紹了使用lua+redis解決發(fā)多張券的并發(fā)問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • RedisTemplate批量操作工具類性能測試

    RedisTemplate批量操作工具類性能測試

    這篇文章主要為大家介紹了RedisTemplate批量操作工具類性能測試詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08

最新評(píng)論

逊克县| 赤峰市| 塔河县| 上林县| 鹰潭市| 佳木斯市| 卢龙县| 葫芦岛市| 彭阳县| 仁怀市| 西乌珠穆沁旗| 格尔木市| 紫阳县| 宁安市| 大理市| 北安市| 饶河县| 三门峡市| 商洛市| 萨迦县| 额尔古纳市| 拜城县| 漠河县| 巨鹿县| 大洼县| 河南省| 齐河县| 郧西县| 彰化市| 黔东| 绥滨县| 财经| 贵定县| 勐海县| 华安县| 松江区| 红桥区| 桂平市| 宁国市| 银川市| 阜阳市|