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

如何在现有Spring应用中为Web服务及数据库调用实现缓存?

Great question! Implementing caching across all web services and database calls in an existing Spring app can drastically boost performance, reduce database load, and improve user experience—if done right. Below is a battle-tested, maintainable approach I’ve used in multiple production projects, covering design patterns, caching mechanisms, Spring-specific tools, and critical best practices:

1. Core Design Patterns to Adopt

These patterns will help you integrate caching without rewriting your entire codebase:

  • Decorator Pattern (DAO/Database Layer): Wrap your existing repository/DAO implementations with caching logic. This keeps your data access code clean and separates caching concerns. Spring Cache’s annotations (like @Cacheable) act as a declarative decorator here—no need to write wrapper classes manually.
  • Proxy Pattern (Service Layer): Use Spring AOP to create proxies around service methods that handle repeated database calls. The proxy intercepts method calls, checks the cache first, and only hits the database if the data isn’t cached. This is exactly how Spring Cache works under the hood.
  • HTTP Cache Pattern (Web Layer): Combine server-side caching with HTTP-level caching headers (Cache-Control, ETag, Last-Modified) to let browsers and CDNs cache responses directly. This reduces unnecessary requests to your backend entirely.
2. Caching Mechanism Selection

Choose the right cache type based on your use case—often a combination works best:

  • Local Caching (Caffeine): For hot, frequently accessed data that doesn’t need to be consistent across application instances (e.g., static configs, user preferences with low update frequency). Caffeine is Spring’s default local cache now—it’s fast, memory-efficient, and supports flexible eviction policies (LRU, LFU).
  • Distributed Caching (Redis): For data that needs to be consistent across multiple app instances (e.g., user session data, shared business data). Redis also supports advanced features like TTL, pub/sub for cache invalidation, and data persistence.
  • Multi-Level Caching: Pair local Caffeine with distributed Redis. Check the local cache first; if a miss occurs, fall back to Redis, then the database. This minimizes network calls to Redis and reduces database load even further.
3. Spring Ecosystem Components to Leverage

Spring has excellent built-in tools to simplify caching integration:

  • Spring Cache Abstraction: The foundation of your caching strategy. It provides a unified API that works with all major cache providers (Caffeine, Redis, etc.). You only need to add annotations to your methods—no provider-specific code.
  • Spring Data Redis: Seamlessly integrates Redis with Spring Cache. Handles serialization/deserialization (use Jackson for JSON serialization instead of JDK serialization for better performance and readability).
  • Spring Web Annotations: Use @CacheControl in your controllers to set HTTP caching headers, or @Cacheable to cache response bodies directly at the web layer.
4. Step-by-Step Implementation Details

Database Call Caching (DAO/Service Layer)

Add caching annotations to your repository or service methods to cache database results:

@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    // Cache the result of findById for 1 hour
    @Cacheable(value = "orders", key = "#id", cacheManager = "redisCacheManager")
    Optional<Order> findById(Long id);

    // Update the cache when saving an order
    @CachePut(value = "orders", key = "#order.id")
    <S extends Order> S save(S order);

    // Evict the cache when deleting an order
    @CacheEvict(value = "orders", key = "#id")
    void deleteById(Long id);
}

Web Service Caching (Controller Layer)

Cache API responses and set HTTP headers to enable client-side caching:

@RestController
@RequestMapping("/api/orders")
public class OrderController {
    @Autowired
    private OrderService orderService;

    @GetMapping("/{id}")
    // Cache the response in Redis for 30 minutes
    @Cacheable(value = "webOrders", key = "#id")
    // Tell browsers/CDNs to cache this response for 10 minutes
    @CacheControl(maxAge = 600, cachePublic = true)
    public ResponseEntity<Order> getOrderById(@PathVariable Long id) {
        return orderService.getOrderById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
}

Cache Configuration (Spring Boot)

Configure your cache providers in application.yml:

Caffeine (Local Cache)

spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=1000,expireAfterAccess=300s # 5 minutes TTL after last access

Redis (Distributed Cache)

spring:
  cache:
    type: redis
    redis:
      time-to-live: 3600000 # 1 hour TTL
      cache-null-values: true # Prevent cache penetration for non-existent data
      use-key-prefix: true # Avoid key collisions across cache namespaces
  data:
    redis:
      host: localhost
      port: 6379
5. Critical Best Practices to Avoid Pitfalls
  • Cache Key Design: Use meaningful, unique keys (e.g., #userId + ":" + #orderId) to avoid collisions. Leverage Spring SpEL expressions for dynamic key generation.
  • Cache Consistency: For data that’s frequently updated, use @CachePut to update the cache when data changes, or @CacheEvict to invalidate stale entries. For complex scenarios, consider database binlog listeners to trigger cache invalidation asynchronously.
  • Mitigate Cache Issues:
    • Cache Penetration: Cache null values (enable cache-null-values in Redis) to avoid repeated database calls for non-existent data.
    • Cache Breakdown: For hot keys, set a longer TTL or use a distributed lock to prevent thundering herd when the cache expires.
    • Cache Avalanche: Add random jitter to TTL values (e.g., expireAfterAccess=300s±30s) so all keys don’t expire at the same time.
  • Monitor Cache Performance: Use Micrometer (integrated with Spring Boot) to track cache hit/miss ratios, eviction counts, and latency. Low hit ratios mean your caching strategy needs adjustment.
  • Test Caching: Write unit tests to verify cache behavior (use @CacheEvict(allEntries = true) in test setup/teardown to avoid test contamination).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:20:38