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

数据库实体缓存工具类样板代码优化的最佳实践咨询

最优解决方案:消除样板代码+规范缓存实现

方案一:使用Spring Cache(推荐的最佳实践)

你提到不确定Spring能否处理缓存,其实Spring Cache是Spring官方提供的缓存抽象,完全可以替代你手动编写的静态缓存,而且能自动处理缓存的命中、更新、过期等逻辑,彻底消除样板代码。

实现步骤:

  1. 引入依赖(Spring Boot项目):
    如果用默认的内存缓存,只需要引入spring-boot-starter-cache;如果想用高性能的本地缓存(比如Caffeine),再加上com.github.ben-manes.caffeine:caffeine依赖。

  2. 开启缓存功能:
    在Spring Boot启动类上添加@EnableCaching注解:

    @SpringBootApplication
    @EnableCaching
    public class YourApplication {
        public static void main(String[] args) {
            SpringApplication.run(YourApplication.class, args);
        }
    }
    
  3. 给数据查询方法添加缓存注解:
    在你的DAO/Service层的查询方法上,用@Cacheable指定缓存名称和缓存Key,Spring会自动缓存查询结果:

    @Repository
    public interface ProductRepository extends JpaRepository<Product, Integer> {
        // 缓存key为传入的id,缓存名称为"products"
        @Cacheable(value = "products", key = "#id")
        Optional<Product> findByIdProduct(Integer id);
    }
    
    @Repository
    public interface CustomerRepository extends JpaRepository<Customer, Integer> {
        @Cacheable(value = "customers", key = "#id")
        Optional<Customer> findById(Integer id);
    }
    
  4. 缓存更新与清理:
    当数据发生修改时,用@CachePut更新缓存,@CacheEvict清理缓存:

    // 更新Product缓存
    @CachePut(value = "products", key = "#product.idProduct")
    Product save(Product product);
    
    // 删除Product缓存
    @CacheEvict(value = "products", key = "#id")
    void deleteByIdProduct(Integer id);
    

这种方式完全不需要你手动维护静态列表和重复的查找方法,Spring会自动处理所有缓存逻辑,还支持切换不同的缓存实现(比如Redis用于分布式场景)。

方案二:手动实现通用缓存(适合不想用Spring Cache的场景)

如果坚持自己实现缓存,可以用泛型+函数式接口封装重复的查找逻辑,避免编写大量样板代码:

实现通用缓存管理器:

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

@Component // 交给Spring管理,单例使用
public class GenericCacheManager {
    // 用Map存储不同类型的实体缓存,key为实体类的Class对象
    private final Map<Class<?>, List<?>> entityCache = new ConcurrentHashMap<>();

    // 初始化缓存:从数据库加载数据存入缓存
    public <T> void loadCache(Class<T> entityClass, List<T> dataList) {
        entityCache.put(entityClass, dataList);
    }

    // 通用根据ID查找方法:传入实体类、目标ID、获取实体ID的函数
    @SuppressWarnings("unchecked")
    public <T, ID> T findById(Class<T> entityClass, ID targetId, Function<T, ID> idGetter) {
        List<T> dataList = (List<T>) entityCache.get(entityClass);
        if (dataList == null) {
            return null;
        }
        return dataList.stream()
                .filter(entity -> targetId.equals(idGetter.apply(entity)))
                .findFirst()
                .orElse(null);
    }
}

使用方式:

  1. 初始化缓存(比如在项目启动时):

    // 加载Product缓存
    genericCacheManager.loadCache(Product.class, productRepository.findAll());
    // 加载Customer缓存
    genericCacheManager.loadCache(Customer.class, customerRepository.findAll());
    
  2. 查找实体:

    // 查找ID为1的Product
    Product product = genericCacheManager.findById(Product.class, 1, Product::getIdProduct);
    // 查找ID为2的Customer
    Customer customer = genericCacheManager.findById(Customer.class, 2, Customer::getId);
    

这种方式不管新增多少实体,都不需要编写新的查找方法,只需要调用通用方法即可,但需要注意:数据更新时要手动调用loadCache刷新缓存列表,否则会出现缓存不一致的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:50:27