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

Spring Cache 最佳實踐總結

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

Spring Cache 深度解析

一、什么是 Spring Cache

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

關鍵特性

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

二、核心注解與生命周期

1.@Cacheable:查詢緩存

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

@Service
public class UserService {
    // 緩存key為用戶ID,緩存不存在時查詢數(shù)據(jù)庫
    @Cacheable(value = "users", key = "#id")
    public User getUser(Long id) {
        return userMapper.selectById(id); // 僅緩存未命中時執(zhí)行
    }
    // 支持條件緩存:僅當id > 100時緩存
    @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 表達式生成緩存 Key
  2. 根據(jù) value/cacheNames 定位緩存對象
  3. 查詢緩存:
    • 命中:直接返回緩存值(方法體不執(zhí)行)
    • 未命中:執(zhí)行方法 → 將返回值存入緩存 → 返回結果

2.@CachePut:更新緩存

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

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

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

3.@CacheEvict:清除緩存

作用:刪除緩存項,通常用于刪除或修改操作。

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

4.@Caching:組合操作

作用:單個方法上組合多個緩存操作。

@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:類級別統(tǒng)一配置

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

@Service
@CacheConfig(cacheNames = "users")
public class UserService {
    @Cacheable(key = "#id") // 無需重復指定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();
        // 全局默認配置
        cacheManager.setCaffeine(Caffeine.newBuilder()
            .initialCapacity(100)
            .maximumSize(500)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .recordStats()); // 開啟統(tǒng)計
        // 為特定緩存區(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)) // 默認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小時過期
            .build();
    }
}

Spring Boot 自動配置

  • 引入 spring-boot-starter-data-redis 自動配置 RedisCacheManager
  • 引入 spring-boot-starter-cache + caffeine 自動配置 CaffeineCacheManager

四、緩存 Key 生成策略

默認策略

  • 無參數(shù):SimpleKey.EMPTY
  • 單個參數(shù):參數(shù)值作為 Key(如 "100"
  • 多個參數(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();
        };
    }
}

五、應用場景與解決方案

1. 緩存穿透(Cache Penetration)

場景:查詢不存在的數(shù)據(jù),大量請求直達數(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; // 緩存空對象
}

2. 緩存擊穿(Cache Breakdown)

場景:熱點數(shù)據(jù)過期瞬間,大量請求涌入數(shù)據(jù)庫。

解決方案

// 設置熱點數(shù)據(jù)永不過期 + 后臺異步更新
@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)

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

解決方案

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

4. 緩存與事務一致性

問題:事務未提交,緩存已更新,導致臟讀。

解決方案

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

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

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

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

2. 暴露監(jiā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 自動暴露 /actuator/caches 端點,可查看和清除緩存。

七、最佳實踐總結

?推薦使用

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

??注意事項

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

??性能對比

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

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

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

相關文章

  • JavaWeb-WebSocket瀏覽器服務器雙向通信方式

    JavaWeb-WebSocket瀏覽器服務器雙向通信方式

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

    Java I/O技術之文件操作詳解

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

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

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

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

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

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

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

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

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

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

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

    詳細介紹SpringCloud之Ribbon

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

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

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

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

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

最新評論

上饶县| 新兴县| 玛多县| 葫芦岛市| 秦皇岛市| 雷波县| 承德市| 永宁县| 鄢陵县| 和政县| 青神县| 宜州市| 京山县| 新乡县| 凤台县| 常熟市| 郯城县| 长葛市| 荃湾区| 泸州市| 扎赉特旗| 南皮县| 简阳市| 胶州市| 普兰县| 旬阳县| 蒲城县| 鄂尔多斯市| 平塘县| 大新县| 喀喇沁旗| 津市市| 淮北市| 永和县| 北宁市| 木兰县| 怀集县| 江城| 宣汉县| 武定县| 昭通市|