用 Optional.orElseGet 实现缓存兜底,核心是延迟执行重建逻辑:缓存命中返回 Optional.of(value),未命中返回 Optional.empty();orElseGet 中放轻量重建操作并回写缓存,避免 orElse 提前实例化导致性能浪费。

用 Optional.orElseGet 实现缓存兜底,核心在于把“查缓存失败后的重建逻辑”延迟执行、按需触发,避免无谓的计算或远程调用。
缓存查询返回 Optional 而非 null
分布式缓存(如 Redis)客户端通常不直接返回 Optional,需手动包装。关键不是“有没有值”,而是“要不要执行备用逻辑”。建议统一封装缓存访问层:
- 查缓存命中 → 返回
Optional.of(value) - 查缓存未命中(或反序列化失败)→ 返回
Optional.empty(),不抛异常、不走 fallback 方法体
orElseGet 里放轻量重建逻辑
orElseGet 接收的是 Supplier,函数式接口,只在 Optional 为空时才执行。适合放入:数据库查询、本地计算、调用降级服务等——但要注意它同步阻塞,不适合重 IO 操作(除非你明确接受延迟)。
示例:
String userId = "123";
Optional<user> cached = cacheClient.get("user:" + userId, User.class);
User user = cached.orElseGet(() -> {
// 只有缓存没取到时才查 DB
return userMapper.selectById(userId);
});
</user>
避免 orElse 和 orElseGet 混用导致性能陷阱
orElse(new ExpensiveObject()) 会**立即构造对象**,哪怕缓存命中的时候也白干;而 orElseGet(() -> new ExpensiveObject()) 是懒加载。在分布式场景下,一次误用可能引发不必要的 DB 查询、HTTP 调用或序列化开销。
- ✅ 正确:用
orElseGet包裹远程/IO 操作 - ❌ 错误:用
orElse直接传 new 实例或方法调用结果
结合缓存写入做原子兜底(推荐模式)
单纯读取 + 重建还不够健壮。更优做法是在 orElseGet 中完成重建后,顺手回写缓存(注意设置合理过期时间),让下次请求直击缓存:
User user = cached.orElseGet(() -> {
User fresh = userMapper.selectById(userId);
if (fresh != null) {
cacheClient.set("user:" + userId, fresh, 10, TimeUnit.MINUTES);
}
return fresh;
});
注意判空和异常处理(例如 DB 查询失败时可抛出或返回默认对象),否则缓存穿透风险仍在。










