Spring中如何像操作集合一样操作缓存?求可行解决方案
解决方案:完善本地缓存同步的Service实现
我明白你想要实现的核心需求:在成功保存数据到数据库后,把最新的持久化数据同步到本地的ConcurrentHashMap缓存中,对吧?你原来的代码思路是对的,但缺少了关键的缓存赋值逻辑,还有一些细节可以优化来保证代码的可靠性和规范性。
修正后的完整可运行代码
@Service public class FooCachedService { // 用构造注入替代@Autowired,更符合Spring最佳实践且便于测试 private final MyDataRepository dataRepository; // 明确泛型类型,避免类型转换问题 private final ConcurrentHashMap<Long, Data> cache = new ConcurrentHashMap<>(); public FooCachedService(MyDataRepository dataRepository) { this.dataRepository = dataRepository; } public Data save(Data data) { // 先完成数据库持久化操作 Data savedData = dataRepository.save(data); // 仅当保存成功(ID不为空)且缓存key(recipient)有效时更新缓存 if (savedData.getId() != null && data.getRecipient() != null) { // 将保存后的完整数据存入缓存,key为recipient cache.put(data.getRecipient(), savedData); } // 返回持久化后的对象,供调用方使用 return savedData; } // 新增缓存查询方法,方便业务侧直接从缓存获取数据 public Optional<Data> getCachedData(Long recipient) { return Optional.ofNullable(cache.get(recipient)); } }
关键优化点说明
- 构造注入:替代
@Autowired字段注入,这是Spring官方推荐的注入方式,能避免空指针问题,同时让单元测试更容易Mock依赖。 - 泛型明确化:给ConcurrentHashMap指定
<Long, Data>泛型,避免后续使用缓存时的强制类型转换,代码更安全清晰。 - 非空校验:增加对
data.getRecipient()的非空判断,防止因recipient为null导致的缓存操作异常。 - 缓存与数据库一致性:确保只有数据库保存成功后才更新缓存,避免缓存中存在未持久化的无效数据。
进阶优化建议
如果你的业务需要更完善的缓存能力,可以考虑以下方向:
- 缓存自动过期:如果不想让缓存永久存在,可以替换ConcurrentHashMap为Caffeine或Guava Cache,实现自动过期和容量限制:
// 引入Caffeine依赖后使用示例 private final Cache<Long, Data> cache = Caffeine.newBuilder() .expireAfterWrite(15, TimeUnit.MINUTES) // 写入后15分钟过期 .maximumSize(2000) // 最大缓存2000条数据 .build(); // 保存时的缓存操作改为 cache.put(data.getRecipient(), savedData); // 查询时改为 return Optional.ofNullable(cache.getIfPresent(recipient));
- 异常安全处理:如果需要更严谨的错误控制,可以给数据库保存操作增加try-catch,确保保存失败时不会更新缓存:
public Data save(Data data) { Data savedData; try { savedData = dataRepository.save(data); if (savedData.getId() != null && data.getRecipient() != null) { cache.put(data.getRecipient(), savedData); } } catch (RuntimeException e) { // 数据库保存失败,不更新缓存,直接抛出异常 throw new RuntimeException("Failed to save data", e); } return savedData; }
- 缓存一致性维护:如果存在其他修改数据库的操作(比如update/delete),记得同步更新或删除对应的缓存条目,避免缓存脏数据。
内容的提问来源于stack exchange,提问作者Denis Stephanov
相关产品推荐
相关产品推荐

