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

如何将现有Map缓存改造为Spring @Cacheable实现

如何用Spring Cache替代手动HashMap缓存

看起来你是把Spring Cache的注解用错啦😉,@CacheEvict是用来删除缓存条目的,而你需要的是在插入数据时写入缓存,应该用@CachePut才对。下面一步步教你把手动HashMap缓存替换成Spring Cache,彻底摆脱手动维护缓存的麻烦:

1. 先开启Spring Cache支持

首先要在你的Spring配置类上加上@EnableCaching注解,这是启用Spring Cache功能的前提:

@Configuration
@EnableCaching
public class CacheConfig {
    // 可选:自定义缓存管理器,默认会用ConcurrentMapCacheManager,也可以换成Redis等分布式缓存
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("customer");
    }
}

2. 改造数据插入逻辑:用@CachePut写入缓存

你原来的代码是手动调用cache.put()把前端ID和数据库生成的ID存入HashMap,现在换成@CachePut注解,它会在方法执行完成后,把返回值自动存入指定缓存:

@Service
public class CustomerService {
    // 删掉原来的手动HashMap,Spring Cache会帮你管理
    // private Map<String, Integer> cache = new HashMap<>();

    private final DSLContext dsl;

    // 构造注入Jooq的DSLContext
    public CustomerService(DSLContext dsl) {
        this.dsl = dsl;
    }

    public void insert(List<Customer> customers) {
        for (Customer customer : customers) {
            // 转换Customer为Jooq生成的CustomerRecord
            CustomerRecord record = dsl.newRecord(CUSTOMER, customer);
            // 调用带@CachePut的方法,自动写入缓存
            saveAndCacheCustomer(record);
        }
    }

    // 单个记录的存储+缓存写入
    @CachePut(value = "customer", key = "#record.frontId")
    public Integer saveAndCacheCustomer(CustomerRecord record) {
        record.store(); // 执行数据库插入
        return record.getId(); // 返回的ID会被存入缓存,key是frontId
    }
}

3. 改造查询逻辑:用@Cacheable自动命中缓存

你的find方法原来只查本地HashMap,现在换成@Cacheable,它会先检查缓存:如果缓存中有对应frontId的条目,直接返回;如果没有,就执行方法体的数据库查询,再把结果存入缓存:

@Cacheable(value = "customer", key = "#frontId")
public Integer find(String frontId) {
    // 这里添加数据库查询逻辑,当缓存未命中时执行
    return dsl.select(CUSTOMER.ID)
            .from(CUSTOMER)
            .where(CUSTOMER.FRONT_ID.eq(frontId))
            .fetchOneInto(Integer.class);
}

关键注意事项

  • 注解生效的前提:被@CachePut、@Cacheable标注的方法必须是Spring管理的Bean的方法,而且不能在同一个类内部直接调用(否则Spring AOP无法拦截,注解不生效)。如果必须在类内部调用,可以通过注入自身Bean的方式调用,或者把缓存相关方法抽成单独的Service。
  • SpEL表达式正确性:key="#record.frontId"要确保能正确获取到前端传入的ID,如果你方法参数是Customer对象,就改成key="#customer.frontId",根据实际参数调整。
  • 缓存的扩展性:默认的ConcurrentMapCacheManager是内存缓存,适合单实例应用;如果是分布式应用,直接换成Redis缓存管理器即可,代码逻辑不需要改动。

这样改造后,你就彻底摆脱了手动维护HashMap的麻烦,Spring Cache会自动帮你处理缓存的写入、读取和过期(如果配置的话)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:18:41