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

JAVA緩存的使用RedisCache、LocalCache、復(fù)合緩存的操作

 更新時(shí)間:2026年02月05日 10:15:17   作者:Demon_Hao  
RedisCache是基于Redis的緩存,數(shù)據(jù)存儲(chǔ)在內(nèi)存中,并且可以被多個(gè)應(yīng)用實(shí)例共享,屬于分布式緩存,本文給大家介紹JAVA緩存的使用RedisCache、LocalCache、復(fù)合緩存的相關(guān)操作,感興趣的朋友跟隨小編一起看看吧

1??RedisCache(分布式緩存)

概念
RedisCache 是基于 Redis 的緩存,數(shù)據(jù)存儲(chǔ)在內(nèi)存中,并且可以被多個(gè)應(yīng)用實(shí)例共享,屬于分布式緩存。

優(yōu)點(diǎn)

  • 高性能:Redis 在內(nèi)存中讀寫,速度非??欤ê撩爰壣踔廖⒚爰墸?。
  • 分布式共享:多個(gè)應(yīng)用實(shí)例可以共享同一份緩存,保證數(shù)據(jù)一致性。
  • 持久化:可以選擇持久化策略(RDB/AOF),重啟后緩存不會(huì)完全丟失。
  • 功能豐富:支持?jǐn)?shù)據(jù)結(jié)構(gòu)(String、Hash、List、Set、SortedSet)、過期策略、訂閱/發(fā)布等。
  • 擴(kuò)展性強(qiáng):可以通過 Redis Cluster 支持水平擴(kuò)展,適合大規(guī)模系統(tǒng)。

缺點(diǎn)(順便提醒)

  • 網(wǎng)絡(luò)訪問會(huì)增加延遲,尤其在高并發(fā)場景下。
  • 內(nèi)存有限,數(shù)據(jù)量太大時(shí)成本高。
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NonNull;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
/**
 * Redis緩存工具類
 */
@Slf4j
@Component
public class RedisCacheTemplate {
    @Resource
    private StringRedisTemplate redisTemplate;
    @Resource
    private ObjectMapper objectMapper;
    /**
     * 指定TypeReference類型獲取數(shù)據(jù)
     */
    public <T> T get(@NonNull String key, @NonNull Duration duration, @NonNull TypeReference<T> clazz, @NonNull Supplier<T> supplier) {
        return getT(key, duration, supplier, strValue -> {
            try {
                return objectMapper.readValue(strValue, clazz);
            } catch (Exception e) {
                log.error("Redis反序列化失敗,KEY:{}", key, e);
                throw new RuntimeException(e);
            }
        });
    }
    /**
     * Class類型獲取數(shù)據(jù)
     */
    public <T> T get(@NonNull String key, @NonNull Duration duration, @NonNull Class<T> clazz, @NonNull Supplier<T> supplier) {
        return getT(key, duration, supplier, strValue -> {
            try {
                return objectMapper.readValue(strValue, clazz);
            } catch (Exception e) {
                log.error("Redis反序列化失敗,KEY:{}", key, e);
                throw new RuntimeException(e);
            }
        });
    }
    /**
     * 寫入數(shù)據(jù)
     */
    public <T> void set(@NonNull String key, @NonNull Duration duration, @NonNull T object) {
        String redisKey = this.buildKey(key);
        try {
            String json = objectMapper.writeValueAsString(object);
            redisTemplate.opsForValue().set(redisKey, json, duration);
        } catch (JsonProcessingException e) {
            log.error("Redis序列化失敗,KEY:{}", key, e);
            throw new RuntimeException(e);
        }
    }
    /**
     * 移除數(shù)據(jù)
     */
    public void del(@NonNull String key) {
        String redisKey = this.buildKey(key);
        redisTemplate.delete(redisKey);
    }
    /**
     * 公共業(yè)務(wù)代碼處理
     */
    private <T> @Nullable T getT(@NotNull String key, @NotNull Duration duration, @NotNull Supplier<T> supplier, Function<String, T> deserialize) {
        String redisKey = this.buildKey(key);
        String strValue = redisTemplate.opsForValue().get(redisKey);
        if (Objects.isNull(strValue)) {
            T value = supplier.get();
            if (Objects.nonNull(value)) {
                this.set(key, duration, value);
            }
            return value;
        } else {
            return deserialize.apply(strValue);
        }
    }
    /**
     * Redis的KEY拼接
     */
    private String buildKey(String key) {
        return "test:cache:" + key;
    }
}
// 使用方式
public static void main(String[] args) {
    private static final TypeReference<List<String>> LIST_TEST = new TypeReference<>() {
    };
    @Resource
    private RedisCacheTemplate redisCacheTemplate;
    List<String> strings = redisCacheTemplate.get(RedisKey.TEST_LIST, Duration.ofMinutes(60), LIST_TEST, () -> {
        System.out.println("TEST");
        return List.of("Test");
    });
}

2??LocalCache(本地緩存)

概念
LocalCache 是應(yīng)用本地內(nèi)存緩存,數(shù)據(jù)只存在于當(dāng)前應(yīng)用實(shí)例的內(nèi)存里,常見實(shí)現(xiàn)有 Guava Cache、Caffeine。

優(yōu)點(diǎn)

  • 超低延遲:數(shù)據(jù)在本地內(nèi)存,訪問速度最快(納秒到微秒級)。
  • 簡單易用:不依賴外部組件,集成方便。
  • 降低網(wǎng)絡(luò)壓力:讀寫緩存不需要通過網(wǎng)絡(luò)訪問 Redis。
  • 可配置豐富:支持過期策略、容量限制、LRU/LFU 等緩存淘汰策略。

缺點(diǎn)

  • 數(shù)據(jù)不共享:多實(shí)例部署時(shí),每個(gè)實(shí)例都有一份獨(dú)立緩存,可能出現(xiàn)數(shù)據(jù)不一致。
  • 內(nèi)存受限:緩存太大可能會(huì)占用應(yīng)用內(nèi)存,影響 JVM 性能。
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Expiry;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NonNull;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
/**
 * Caffeine本地緩存工具類
 */
@Slf4j
@Component
public class LocalCacheTemplate {
    /**
     * JVM 全局緩存
     * 存儲(chǔ) CacheValue 包裝對象,支持每條緩存獨(dú)立 TTL
     */
    private static final Cache<String, CacheValue<Object>> CACHE = Caffeine.newBuilder()
        // LRU 淘汰:數(shù)量滿了移除長時(shí)間未訪問或最早的數(shù)據(jù)
        .maximumSize(30000)
        // TTL 過期:按時(shí)間清理
        .expireAfter(new Expiry<String, CacheValue<Object>>() {
            @Override
            public long expireAfterCreate(@NotNull String key, @NotNull CacheValue<Object> value, long currentTime) {
                return value.ttlNanos();
            }
            @Override
            public long expireAfterUpdate(@NotNull String key, @NotNull CacheValue<Object> value, long currentTime, long currentDuration) {
                return value.ttlNanos();
            }
            @Override
            public long expireAfterRead(@NotNull String key, @NotNull CacheValue<Object> value, long currentTime, long currentDuration) {
                // 讀取不改變 TTL
                return currentDuration;
            }
        }).build();
    @Resource
    private ObjectMapper objectMapper;
    /**
     * 判斷KEY是否存在(非強(qiáng)一致,僅用于弱判斷)
     */
    public boolean exists(@NonNull String key) {
        String redisKey = this.buildKey(key);
        return CACHE.getIfPresent(redisKey) != null;
    }
    /**
     * 獲取KEY數(shù)據(jù)
     */
    public <T> T get(@NonNull String key, @NonNull Class<T> clazz) {
        String redisKey = this.buildKey(key);
        CacheValue<Object> wrapper = CACHE.getIfPresent(redisKey);
        return getT(key, clazz, wrapper);
    }
    /**
     * Class類型獲取數(shù)據(jù),沒有就寫入
     */
    public <T> T get(@NonNull String key, @NonNull Duration duration, @NonNull Class<T> clazz, @NonNull Supplier<T> supplier) {
        String redisKey = this.buildKey(key);
        CacheValue<Object> wrapper = CACHE.get(redisKey, k -> new CacheValue<>(supplier.get(), duration.toNanos()));
        return getT(key, clazz, wrapper);
    }
    /**
     * 指定TypeReference類型獲取數(shù)據(jù),沒有就寫入
     */
    public <T> T get(@NonNull String key, @NonNull Duration duration, @NonNull TypeReference<T> clazz, @NonNull Supplier<T> supplier) {
        String redisKey = this.buildKey(key);
        CacheValue<Object> wrapper = CACHE.get(redisKey, k -> new CacheValue<>(supplier.get(), duration.toNanos()));
        if (wrapper == null || wrapper.value() == null) {
            return null;
        }
        return getSerialize(key, wrapper.value(), strValue -> objectMapper.convertValue(strValue, clazz));
    }
    /**
     * 寫入數(shù)據(jù)
     */
    public void set(@NonNull String key, @NonNull Duration duration, @NonNull Object value) {
        String redisKey = this.buildKey(key);
        CACHE.put(redisKey, new CacheValue<>(value, duration.toNanos()));
    }
    /**
     * 移除數(shù)據(jù)
     */
    public void del(@NonNull String key) {
        String redisKey = this.buildKey(key);
        CACHE.invalidate(redisKey);
    }
    /**
     * 公共業(yè)務(wù)代碼處理
     */
    private <T> @Nullable T getT(@NotNull String key, @NotNull Class<T> clazz, CacheValue<Object> wrapper) {
        if (wrapper == null || wrapper.value() == null) {
            return null;
        }
        Object value = wrapper.value();
        // 已經(jīng)是目標(biāo)類型
        if (clazz.isInstance(value)) {
            return clazz.cast(value);
        }
        return getSerialize(key, value, strValue -> objectMapper.convertValue(strValue, clazz));
    }
    /**
     * 序列化操作
     */
    private <T> @Nullable T getSerialize(@NotNull String key, @NotNull Object object, Function<Object, T> deserialize) {
        try {
            return deserialize.apply(object);
        } catch (Exception e) {
            log.error("本地緩存序列化失敗,KEY:{}", key, e);
            throw new RuntimeException(e);
        }
    }
    /**
     * Redis的KEY拼接
     */
    private String buildKey(String key) {
        return "test:cache:" + key;
    }
    /**
     * 存儲(chǔ)數(shù)據(jù)和過期時(shí)間
     *
     * @param value    內(nèi)容
     * @param ttlNanos 過期時(shí)間
     */
    public record CacheValue<T>(T value, long ttlNanos) {
    }
}
// 使用方式
public static void main(String[] args) {
    private static final TypeReference<List<String>> LIST_TEST = new TypeReference<>() {
    };
    @Resource
    private LocalCacheTemplate localCacheTemplate;
    List<String> strings = localCacheTemplate.get(RedisKey.TEST_LIST, Duration.ofMinutes(60), LIST_TEST, () -> {
        System.out.println("TEST");
        return List.of("Test");
    });
}

3??復(fù)合緩存(Composite Cache / Two-level Cache)

概念
復(fù)合緩存結(jié)合了 LocalCache + RedisCache,常見模式是:

  • 一級緩存(LocalCache):應(yīng)用本地內(nèi)存,快速響應(yīng)。
  • 二級緩存(RedisCache):共享分布式緩存,保證跨實(shí)例一致性。

優(yōu)點(diǎn)

  • 速度快:大部分熱點(diǎn)數(shù)據(jù)在本地緩存,訪問本地即可,減少網(wǎng)絡(luò)請求。
  • 一致性保證:Redis 做二級緩存,確??鐚?shí)例數(shù)據(jù)一致。
  • 降低壓力:Redis 熱點(diǎn)數(shù)據(jù)由本地緩存緩沖,降低 Redis 壓力。
  • 靈活性高:可以對不同數(shù)據(jù)設(shè)置不同的緩存策略(本地緩存過期時(shí)間短,Redis 過期時(shí)間長)。
  • 可擴(kuò)展性強(qiáng):支持高并發(fā),結(jié)合分布式和本地緩存的優(yōu)勢。

缺點(diǎn)

  • 實(shí)現(xiàn)復(fù)雜,需要處理緩存一致性問題(如本地緩存與 Redis 的同步)。
  • 本地緩存失效策略設(shè)計(jì)不當(dāng)可能導(dǎo)致緩存雪崩或臟數(shù)據(jù)。
import com.fasterxml.jackson.core.type.TypeReference;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.jspecify.annotations.NonNull;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.function.Supplier;
/**
 * 本地緩存和Redis緩存實(shí)現(xiàn)復(fù)合緩存工具類
 */
@Slf4j
@Component
public class CompoundCacheTemplate {
    // 默認(rèn)10分鐘
    public static Duration duration = Duration.ofMinutes(10);
    @Resource
    private RedisCacheTemplate redisCacheTemplate;
    @Resource
    private LocalCacheTemplate localCacheTemplate;
    /**
     * 獲取KEY數(shù)據(jù)
     */
    public <T> T get(@NonNull String key, @NonNull Class<T> clazz) {
        // 先查本地緩存
        T value = localCacheTemplate.get(key, clazz);
        if (value != null) {
            return value;
        }
        // 再查Redis
        value = redisCacheTemplate.get(key, duration, clazz, () -> null);
        if (value != null) {
            // 回寫本地緩存
            localCacheTemplate.set(key, Duration.ofMinutes(10), value);
        }
        return value;
    }
    /**
     * Class類型獲取數(shù)據(jù),沒有就寫入
     */
    public <T> T get(@NonNull String key, @NonNull Duration duration, @NonNull Class<T> clazz, @NonNull Supplier<T> supplier) {
        // 先查本地緩存
        T value = localCacheTemplate.get(key, clazz);
        if (value != null) {
            return value;
        }
        // 查Redis,如果沒有就調(diào)用業(yè)務(wù)邏輯
        value = redisCacheTemplate.get(key, duration, clazz, supplier);
        if (value != null) {
            // 回寫本地緩存
            localCacheTemplate.set(key, duration, value);
        }
        return value;
    }
    /**
     * 指定TypeReference類型獲取數(shù)據(jù),沒有就寫入
     */
    public <T> T get(@NonNull String key, @NonNull Duration duration, @NonNull TypeReference<T> clazz, @NonNull Supplier<T> supplier) {
        // 先查本地緩存
        T value = localCacheTemplate.get(key, duration, clazz, () -> null);
        if (value != null) {
            return value;
        }
        // 查Redis,如果沒有就調(diào)用業(yè)務(wù)邏輯
        value = redisCacheTemplate.get(key, duration, clazz, supplier);
        if (value != null) {
            // 回寫本地緩存
            localCacheTemplate.set(key, duration, value);
        }
        return value;
    }
    /**
     * 寫入數(shù)據(jù)
     */
    public void set(@NonNull String key, @NonNull Duration duration, @NonNull Object value) {
        // 同步寫入本地緩存和Redis
        localCacheTemplate.set(key, duration, value);
        redisCacheTemplate.set(key, duration, value);
    }
    /**
     * 移除數(shù)據(jù)
     */
    public void del(@NonNull String key) {
        // 同步刪除本地緩存和Redis
        localCacheTemplate.del(key);
        redisCacheTemplate.del(key);
    }
}
// 使用方式
public static void main(String[] args) {
    private static final TypeReference<List<String>> LIST_TEST = new TypeReference<>() {
    };
    @Resource
    private CompoundCacheTemplate compoundCacheTemplate;
    List<String> strings = compoundCacheTemplate.get(RedisKey.TEST_LIST, Duration.ofMinutes(60), LIST_TEST, () -> {
        System.out.println("TEST");
        return List.of("Test");
    });
}

到此這篇關(guān)于JAVA緩存的使用RedisCache、LocalCache、復(fù)合緩存的操作的文章就介紹到這了,更多相關(guān)java rediscache localcache 復(fù)合緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring ApplicationListener監(jiān)聽器用法詳解

    Spring ApplicationListener監(jiān)聽器用法詳解

    這篇文章主要介紹了Spring ApplicationListener監(jiān)聽器用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Flink部署集群整體架構(gòu)源碼分析

    Flink部署集群整體架構(gòu)源碼分析

    這篇文章主要為大家介紹了Flink部署集群及整體架構(gòu)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • JAVA提高第九篇 集合體系

    JAVA提高第九篇 集合體系

    這篇文章主要為大家詳細(xì)介紹了JAVA提高第九篇集合體系的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Springboot集成swagger實(shí)現(xiàn)方式

    Springboot集成swagger實(shí)現(xiàn)方式

    這篇文章主要介紹了Springboot集成swagger實(shí)現(xiàn)方式,通過簡單的示例代碼詳細(xì)描述了實(shí)現(xiàn)過程步驟,有需要的朋友可以借鑒參考下,希望可以有所幫助
    2021-08-08
  • Intellij Idea中進(jìn)行Mybatis逆向工程的實(shí)現(xiàn)

    Intellij Idea中進(jìn)行Mybatis逆向工程的實(shí)現(xiàn)

    這篇文章主要介紹了Intellij Idea中進(jìn)行Mybatis逆向工程的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Eclipse中實(shí)現(xiàn)JS代碼提示功能(圖文教程)

    Eclipse中實(shí)現(xiàn)JS代碼提示功能(圖文教程)

    本文通過圖文并茂的形式給大家介紹了Eclipse中實(shí)現(xiàn)JS代碼提示功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2017-11-11
  • java線程之join方法的使用介紹

    java線程之join方法的使用介紹

    本篇文章介紹了,java線程之join方法的使用分析,需要的朋友參考下
    2013-05-05
  • MyBatis使用注解開發(fā)實(shí)現(xiàn)步驟解析

    MyBatis使用注解開發(fā)實(shí)現(xiàn)步驟解析

    這篇文章主要介紹了MyBatis使用注解開發(fā)實(shí)現(xiàn)步驟解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java中的ReadWriteLock讀寫鎖實(shí)例詳解

    Java中的ReadWriteLock讀寫鎖實(shí)例詳解

    Java中的ReadWriteLock讀寫鎖,它是一種讀寫分離的鎖機(jī)制,適用于讀多寫少的場景,本文通過實(shí)例代碼給大家介紹Java中的ReadWriteLock讀寫鎖,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • Java中二叉樹的先序、中序、后序遍歷以及代碼實(shí)現(xiàn)

    Java中二叉樹的先序、中序、后序遍歷以及代碼實(shí)現(xiàn)

    這篇文章主要介紹了Java中二叉樹的先序、中序、后序遍歷以及代碼實(shí)現(xiàn),一棵二叉樹是結(jié)點(diǎn)的一個(gè)有限集合,該集合或者為空,或者是由一個(gè)根節(jié)點(diǎn)加上兩棵別稱為左子樹和右子樹的二叉樹組成,需要的朋友可以參考下
    2023-11-11

最新評論

阿坝| 略阳县| 河北省| 甘肃省| 余姚市| 新绛县| 靖江市| 连城县| 兴文县| 苏尼特右旗| 平塘县| 剑河县| 怀安县| 宝坻区| 红安县| 贵溪市| 化德县| 河北区| 玛多县| 安泽县| 罗江县| 大姚县| 灌阳县| 张家口市| 疏勒县| 满城县| 惠来县| 平遥县| 和政县| 色达县| 广平县| 佳木斯市| 千阳县| 武鸣县| 兴安盟| 五台县| 江城| 兰州市| 武胜县| 白城市| 东方市|