You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

缓存更新场景:Cache-Control:max-age=0时的缓存处理方案咨询

Got it, let's tackle this cache refresh scenario step by step. Your current setup uses @Cacheable with a condition, but we need to adjust it to handle the max-age=0 case where we bypass cache, fetch fresh data, and update the cache afterward.

Solution Approach

We need to handle two distinct scenarios with Spring Cache annotations:

  • Scenario 1: cacheControl equals max-age=0 → Bypass cache reading, fetch fresh data from the underlying service, and force-update the cache
  • Scenario 2: cacheControl is null or any other value → Prioritize reading from cache; only fetch from the service and write to cache if the cache is empty

Spring Cache's @Cacheable handles "read-first" logic, while @CachePut handles "write-after-execution" logic (it always runs the method and updates the cache). We can combine these two with conditional checks to meet your requirements.

Step 1: Refine Utility Class Methods

First, update your Utils class to add a method that explicitly identifies the force-refresh case (max-age=0):

public class Utils {
    // Original method: Returns true when caching is allowed (not max-age=0)
    public static boolean isCachingAllowed(String cacheControl) {
        return cacheControl == null || !"max-age=0".equals(cacheControl);
    }

    // New method: Returns true when we need to force-refresh the cache
    public static boolean isForceRefresh(String cacheControl) {
        return "max-age=0".equals(cacheControl);
    }

    // Your existing idKey method
    public static String idKey(String id) {
        return "user_data_" + id;
    }
}

Step 2: Combine Annotations with @Caching

Use @Caching to wrap @Cacheable and @CachePut, each with their own conditional logic:

import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Caching;

@Caching(
    cacheable = @Cacheable(
        key = "T(com.org.Utils).idKey(#id)",
        condition = "T(com.org.Utils).isCachingAllowed(#cacheControl)"
    ),
    put = @CachePut(
        key = "T(com.org.Utils).idKey(#id)",
        condition = "T(com.org.Utils).isForceRefresh(#cacheControl)"
    )
)
public UserData get(String id, String cacheControl) {
    // Delegate to your underlying service here
    return underlyingUserDataService.fetchById(id);
}

How It Works

Let's break down the logic for each scenario:

  • When cacheControl = "max-age=0":
    • @Cacheable's condition is false → Skips reading from cache entirely
    • @CachePut's condition is true → Executes the method (fetches fresh data from the service), then updates the cache with the new UserData
  • When cacheControl is null or any other value:
    • @Cacheable's condition is true → First tries to read from cache
      • If cache hits: Returns cached data immediately, skips the method body
      • If cache misses: Executes the method to fetch data, then automatically writes it to cache (default @Cacheable behavior)
    • @CachePut's condition is false → No action taken

Additional Notes

  • If you need to handle other cache-control directives like no-cache, extend the isForceRefresh method:
    public static boolean isForceRefresh(String cacheControl) {
        return cacheControl != null && (cacheControl.contains("max-age=0") || cacheControl.contains("no-cache"));
    }
    
  • Verify your cache provider (Redis, Caffeine, etc.) is properly configured, and ensure the idKey method generates unique keys for each user record
  • Test edge cases: First-time calls (empty cache), cache hits with max-age=0, and regular cache reads to confirm behavior matches expectations

内容的提问来源于stack exchange,提问作者paramupk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:44:16