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

Spring Cache 最佳實(shí)踐總結(jié)

 更新時(shí)間:2026年01月04日 16:01:06   作者:廋到被風(fēng)吹走  
SpringCache是Spring框架提供的聲明式緩存抽象層,通過少量注解即可為應(yīng)用添加緩存能力,無需侵入業(yè)務(wù)代碼,本文給大家介紹Spring Cache 最佳實(shí)踐總結(jié),感興趣的朋友跟隨小編一起看看吧

Spring Cache 深度解析

一、什么是 Spring Cache

Spring Cache 是 Spring 框架提供的聲明式緩存抽象層,它通過少量注解即可為應(yīng)用添加緩存能力,無需侵入業(yè)務(wù)代碼。核心設(shè)計(jì)目標(biāo)是解耦緩存實(shí)現(xiàn)與業(yè)務(wù)邏輯,支持在運(yùn)行時(shí)靈活切換 EhCache、Redis、Caffeine、Hazelcast 等緩存實(shí)現(xiàn)。

關(guān)鍵特性

  • 聲明式編程:僅通過 @Cacheable、@CacheEvict 等注解實(shí)現(xiàn)緩存
  • 實(shí)現(xiàn)無關(guān)性:接口抽象,支持多種緩存提供者
  • 與 Spring 生態(tài)無縫集成:事務(wù)、AOP、SpEL 表達(dá)式

二、核心注解與生命周期

1.@Cacheable:查詢緩存

作用:方法執(zhí)行前檢查緩存,存在則直接返回,不存在則執(zhí)行方法并將結(jié)果存入緩存。

@Service
public class UserService {
    // 緩存key為用戶ID,緩存不存在時(shí)查詢數(shù)據(jù)庫
    @Cacheable(value = "users", key = "#id")
    public User getUser(Long id) {
        return userMapper.selectById(id); // 僅緩存未命中時(shí)執(zhí)行
    }
    // 支持條件緩存:僅當(dāng)id > 100時(shí)緩存
    @Cacheable(value = "users", key = "#id", condition = "#id > 100")
    public User getVipUser(Long id) {
        return userMapper.selectById(id);
    }
    // 使用SpEL生成key:如 "user:100:admin"
    @Cacheable(value = "users", key = "'user:' + #id + ':' + #type")
    public User getUserByType(Long id, String type) {
        return userMapper.selectByIdAndType(id, type);
    }
}

執(zhí)行流程

  1. 解析 SpEL 表達(dá)式生成緩存 Key
  2. 根據(jù) value/cacheNames 定位緩存對(duì)象
  3. 查詢緩存:
    • 命中:直接返回緩存值(方法體不執(zhí)行)
    • 未命中:執(zhí)行方法 → 將返回值存入緩存 → 返回結(jié)果

2.@CachePut:更新緩存

作用無論緩存是否存在,都執(zhí)行方法,并將結(jié)果更新到緩存。適用于創(chuàng)建或更新操作。

@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
    userMapper.updateById(user);
    return user; // 返回值會(huì)更新到緩存
}

?? 注意@CachePut@Cacheable 不能用在同一方法(邏輯沖突)。

3.@CacheEvict:清除緩存

作用:刪除緩存項(xiàng),通常用于刪除或修改操作。

// 刪除指定key的緩存
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
    userMapper.deleteById(id);
}
// 刪除整個(gè)緩存區(qū)的所有條目
@CacheEvict(value = "users", allEntries = true)
public void clearAllUsers() {
    // 批量刪除后的清理操作
}
// 在方法執(zhí)行前清除緩存(默認(rèn)是執(zhí)行后)
@CacheEvict(value = "users", key = "#id", beforeInvocation = true)
public void deleteUserBefore(Long id) {
    userMapper.deleteById(id);
}

4.@Caching:組合操作

作用:?jiǎn)蝹€(gè)方法上組合多個(gè)緩存操作。

@Caching(
    put = {
        @CachePut(value = "users", key = "#user.id"),
        @CachePut(value = "users", key = "#user.email")
    },
    evict = {
        @CacheEvict(value = "userList", allEntries = true)
    }
)
public User createUser(User user) {
    userMapper.insert(user);
    return user;
}

5.@CacheConfig:類級(jí)別統(tǒng)一配置

作用:在類上統(tǒng)一指定緩存名稱等公共配置,避免重復(fù)書寫。

@Service
@CacheConfig(cacheNames = "users")
public class UserService {
    @Cacheable(key = "#id") // 無需重復(fù)指定value
    public User getUser(Long id) { /*...*/ }
    @CacheEvict(key = "#id")
    public void deleteUser(Long id) { /*...*/ }
}

三、緩存管理器配置

1. 啟用緩存

@SpringBootApplication
@EnableCaching // 啟用緩存功能
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2. 配置 Caffeine 本地緩存(推薦)

@Configuration
public class CacheConfig {
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        // 全局默認(rèn)配置
        cacheManager.setCaffeine(Caffeine.newBuilder()
            .initialCapacity(100)
            .maximumSize(500)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .recordStats()); // 開啟統(tǒng)計(jì)
        // 為特定緩存區(qū)定制配置
        cacheManager.registerCustomCache("users", 
            Caffeine.newBuilder()
                .maximumSize(1000)
                .expireAfterAccess(30, TimeUnit.MINUTES)
                .build());
        return cacheManager;
    }
}

3. 配置 Redis 分布式緩存

@Configuration
public class RedisCacheConfig {
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration
            .defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(30)) // 默認(rèn)30分鐘過期
            .serializeKeysWith(
                RedisSerializationContext.SerializationPair
                    .fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(
                RedisSerializationContext.SerializationPair
                    .fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(factory)
            .cacheDefaults(config)
            .withCacheConfiguration("users", 
                RedisCacheConfiguration
                    .defaultCacheConfig()
                    .entryTtl(Duration.ofHours(2))) // users緩存2小時(shí)過期
            .build();
    }
}

Spring Boot 自動(dòng)配置

  • 引入 spring-boot-starter-data-redis 自動(dòng)配置 RedisCacheManager
  • 引入 spring-boot-starter-cache + caffeine 自動(dòng)配置 CaffeineCacheManager

四、緩存 Key 生成策略

默認(rèn)策略

  • 無參數(shù):SimpleKey.EMPTY
  • 單個(gè)參數(shù):參數(shù)值作為 Key(如 "100"
  • 多個(gè)參數(shù):SimpleKey [arg1, arg2, ...]

自定義 KeyGenerator

@Configuration
public class CacheConfig implements CachingConfigurer {
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getSimpleName())
              .append(":")
              .append(method.getName())
              .append(":");
            // 自定義參數(shù)序列化邏輯
            return sb.toString();
        };
    }
}

五、應(yīng)用場(chǎng)景與解決方案

1. 緩存穿透(Cache Penetration)

場(chǎng)景:查詢不存在的數(shù)據(jù),大量請(qǐng)求直達(dá)數(shù)據(jù)庫。

解決方案

@Cacheable(value = "users", key = "#id", unless = "#result == null")
public User findUser(Long id) {
    return userMapper.selectById(id);
}
// 或使用空值緩存
@Cacheable(value = "users", key = "#id")
public User findUser(Long id) {
    User user = userMapper.selectById(id);
    return user == null ? User.NULL : user; // 緩存空對(duì)象
}

2. 緩存擊穿(Cache Breakdown)

場(chǎng)景:熱點(diǎn)數(shù)據(jù)過期瞬間,大量請(qǐng)求涌入數(shù)據(jù)庫。

解決方案

// 設(shè)置熱點(diǎn)數(shù)據(jù)永不過期 + 后臺(tái)異步更新
@Cacheable(value = "hotData", key = "#key")
public HotData getHotData(String key) {
    return loadFromDatabase(key);
}
// 或使用分布式鎖(Redisson)
@Cacheable(value = "users", key = "#id")
public User getUserWithLock(Long id) {
    RLock lock = redissonClient.getLock("user:lock:" + id);
    try {
        if (lock.tryLock(100, 10, TimeUnit.SECONDS)) {
            return userMapper.selectById(id);
        }
    } finally {
        lock.unlock();
    }
    return null;
}

3. 緩存雪崩(Cache Avalanche)

場(chǎng)景:大量緩存同時(shí)過期,數(shù)據(jù)庫壓力驟增。

解決方案

# application.yml
spring:
  cache:
    caffeine:
      spec: maximumSize=1000,expireAfterWrite=30m,expireAfterAccess=25m
      # 設(shè)置隨機(jī)過期時(shí)間,避免集中失效
      # expireAfterWrite=30m,randomTime=5m

4. 緩存與事務(wù)一致性

問題:事務(wù)未提交,緩存已更新,導(dǎo)致臟讀。

解決方案

@Transactional
@CacheEvict(value = "users", key = "#id", beforeInvocation = true)
public void updateUser(Long id, User user) {
    // beforeInvocation=true 確保事務(wù)回滾時(shí)緩存也被清除
    userMapper.updateById(user);
}

六、緩存監(jiān)控與統(tǒng)計(jì)

1. 開啟 Caffeine 統(tǒng)計(jì)

Caffeine.newBuilder()
    .recordStats()
    .build();

2. 暴露監(jiān)控端點(diǎn)

@Component
public class CacheMetrics {
    @Autowired
    private CacheManager cacheManager;
    @Scheduled(fixedRate = 60000)
    public void printStats() {
        Cache usersCache = cacheManager.getCache("users");
        if (usersCache.getNativeCache() instanceof com.github.benmanes.caffeine.cache.Cache) {
            com.github.benmanes.caffeine.cache.Cache nativeCache = 
                (com.github.benmanes.caffeine.cache.Cache) usersCache.getNativeCache();
            System.out.println("緩存命中率: " + nativeCache.stats().hitRate());
        }
    }
}

Spring Boot Actuator 自動(dòng)暴露 /actuator/caches 端點(diǎn),可查看和清除緩存。

七、最佳實(shí)踐總結(jié)

?推薦使用

  1. 優(yōu)先本地緩存:Caffeine(性能最優(yōu))或 EhCache
  2. 分布式場(chǎng)景:Redis(集群高可用)
  3. Key 設(shè)計(jì)類名:方法名:參數(shù) 格式,如 user:100
  4. TTL 策略:熱點(diǎn)數(shù)據(jù)短過期,冷數(shù)據(jù)長(zhǎng)過期
  5. 異常處理:緩存操作不應(yīng)影響主流程,捕獲異常并降級(jí)
@Cacheable(value = "users", key = "#id")
public User getUser(Long id) {
    try {
        return userMapper.selectById(id);
    } catch (Exception e) {
        log.error("查詢用戶失敗", e);
        return User.EMPTY; // 返回空對(duì)象避免緩存穿透
    }
}

??注意事項(xiàng)

  1. 緩存 Key 必須唯一:避免不同方法數(shù)據(jù)覆蓋
  2. @CachePut:確保返回值為完整數(shù)據(jù),避免緩存不完整對(duì)象
  3. 序列化成本:Redis 緩存注意對(duì)象序列化開銷
  4. 緩存一致性:更新操作必須清除相關(guān)緩存
  5. 大對(duì)象緩存:評(píng)估內(nèi)存占用,避免 OOM

??性能對(duì)比

緩存類型讀取性能寫入性能適用場(chǎng)景
Caffeine極高(本地)極高高頻讀、數(shù)據(jù)量適中
Redis高(網(wǎng)絡(luò))分布式、數(shù)據(jù)共享
EhCache傳統(tǒng)項(xiàng)目、功能豐富

Spring Cache 通過統(tǒng)一的抽象層,讓開發(fā)者以極簡(jiǎn)的注解實(shí)現(xiàn)強(qiáng)大的緩存能力,是提升應(yīng)用性能的必備利器。

到此這篇關(guān)于Spring Cache 最佳實(shí)踐總結(jié)的文章就介紹到這了,更多相關(guān)Spring Cache深度解析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaWeb-WebSocket瀏覽器服務(wù)器雙向通信方式

    JavaWeb-WebSocket瀏覽器服務(wù)器雙向通信方式

    文章介紹了WebSocket協(xié)議的工作原理和應(yīng)用場(chǎng)景,包括與HTTP的對(duì)比,接著,詳細(xì)介紹了如何在Java中使用WebSocket,包括配置類、服務(wù)編寫和前端頁面的實(shí)現(xiàn)
    2025-02-02
  • Java I/O技術(shù)之文件操作詳解

    Java I/O技術(shù)之文件操作詳解

    這篇文章主要介紹了Java I/O技術(shù)之文件操作詳解,需要的朋友可以參考下
    2014-07-07
  • springboot接口如何多次獲取request中的body內(nèi)容

    springboot接口如何多次獲取request中的body內(nèi)容

    這篇文章主要介紹了springboot接口多次獲取request中的body內(nèi)容的過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java 實(shí)戰(zhàn)項(xiàng)目錘煉之網(wǎng)上花店商城的實(shí)現(xiàn)流程

    Java 實(shí)戰(zhàn)項(xiàng)目錘煉之網(wǎng)上花店商城的實(shí)現(xiàn)流程

    讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+jsp+servlet+mysql+ajax實(shí)現(xiàn)一個(gè)網(wǎng)上花店商城系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • springsecurity?登錄認(rèn)證流程分析一(ajax)

    springsecurity?登錄認(rèn)證流程分析一(ajax)

    這篇文章主要介紹了springsecurity?登錄認(rèn)證一(ajax篇),本文通過實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • SpringBoot自定義注解解決公共字段填充問題解決

    SpringBoot自定義注解解決公共字段填充問題解決

    修改時(shí)間,修改人等字段時(shí),這些字段屬于公共字段,本文主要介紹了SpringBoot自定義注解解決公共字段填充問題解決,使用它的好處就是可以統(tǒng)一對(duì)這些字段進(jìn)行處理,感興趣的可以了解一下
    2024-07-07
  • Java實(shí)現(xiàn)Excel表單控件的添加與刪除

    Java實(shí)現(xiàn)Excel表單控件的添加與刪除

    本文通過Java代碼示例介紹如何在Excel表格中添加表單控件,包括文本框、單選按鈕、復(fù)選框、組合框、微調(diào)按鈕等,以及如何刪除Excel中的指定表單控件,需要的可以參考一下
    2022-05-05
  • 詳細(xì)介紹SpringCloud之Ribbon

    詳細(xì)介紹SpringCloud之Ribbon

    本篇文章主要介紹了SpringCloud之Ribbon,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • 基于SpringBoot應(yīng)用監(jiān)控Actuator安全隱患及解決方式

    基于SpringBoot應(yīng)用監(jiān)控Actuator安全隱患及解決方式

    這篇文章主要介紹了SpringBoot應(yīng)用監(jiān)控Actuator安全隱患及解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java多線程實(shí)現(xiàn)之Executor詳解

    Java多線程實(shí)現(xiàn)之Executor詳解

    這篇文章主要介紹了Java多線程實(shí)現(xiàn)之Executor詳解,Executor 給他一個(gè) Runnable,他就能自動(dòng)很安全的幫你把這個(gè)線程執(zhí)行完畢
    Executor 通過創(chuàng)建線程池的方式來管理線程,需要的朋友可以參考下
    2023-08-08

最新評(píng)論

新安县| 屯门区| 郑州市| 永康市| 赫章县| 收藏| 盐源县| 黄大仙区| 华容县| 青铜峡市| 股票| 隆回县| 随州市| 肥城市| 五寨县| 施甸县| 景宁| 剑川县| 偏关县| 富顺县| 儋州市| 赣榆县| 阿克| 仪征市| 资溪县| 崇文区| 宁都县| 德化县| 大新县| 梁山县| 茶陵县| 西昌市| 台山市| 西畴县| 璧山县| 清镇市| 馆陶县| 和田市| 琼结县| 班玛县| 扎囊县|