我们在项目中添加了spring-boot-starter-cache
,没有使用任何特定的缓存提供程序实现。我们通过调用以下方法在应用程序启动期间加载所有数据:
@Override
@Cacheable(cacheNames = "foos")
public List<FooDto> getAllFoo() {
return fooRepository.findAll().stream()
.map(FooEntityDomainToDtoMapper::mapDomainToDto) // mapping entity to dto
.collect(Collectors.toList());
}
//Want to implement something like:
public FooDto getFoo(Long id) {
//return single object from foos(which are cached in above method)
}
它将所有foos
存储在缓存中。正如我们下次期望的那样,当我们调用getAllFoo
时,它是从缓存中返回而不是从数据库中返回。现在,下一次当用户通过id请求单个对象时,我们想从已经缓存的foos
数据中返回它,而不是调用JPA的findById()
。有什么办法可以做到这一点?
答案 0 :(得分:1)
您是否有任何理由想要或需要将所有Foos
缓存在应用程序中而不是单独缓存?
请记住, Spring的缓存抽象是设计使然,它使用方法参数(如果有)作为键,并使用返回值作为缓存条目的值。如果该方法没有参数,则 Spring 将为您生成一个ID。
我有written关于如何自定义 Spring的 CacheManager
实现,以缓存由@Cacheable
方法返回的值的 Collection ,单独。
但是,暂时,假设您确实需要/想要缓存Foos
的整个列表。
然后,要创建一种通过ID从Foo
的“缓存”列表中提取单个Foos
的方法,例如,可以在服务类中给定原始的缓存方法,例如...
@Sevice
class MyFooService {
private final FooRepository<Foo, Long> fooRepository;
@Cacheable(cacheNames = "foos")
public List<FooDto> getAllFoos() {
return this.fooRepository.findAll().stream()
.map(FooEntityDomainToDtoMapper::mapDomainToDto) // mapping entity to dto
.collect(Collectors.toList());
}
}
然后,在另一个应用程序组件中,您可以...
@Component
class MyFooAccessor {
private final MyFooService fooService;
MyFooAccessor(MyFooService fooService) {
this.fooService = fooService;
}
Optional<FooDto> getById(Long id) {
this.fooService.getAllFoos().stream()
.filter(fooDto -> fooDto.getId().equals(id))
.findFirst();
}
...
}
MyFooAccessor
确保您不绕过缓存代理(即,<<>所应用的MyFooService
周围的AOP代理+缓存建议em> Spring )。如果getById(..)
方法是MyFooService
类的成员,并且直接调用了getAllFoos()
方法,则您将绕过代理和缓存建议,从而导致每次访问数据库。
注意:如果要保留缓存代理,可以使用 Spring AOP Load Time Weaving (LTW)(请参阅doc)来避免绕过缓存代理。
getById(:Long)
类中的MyFooService
方法和getAllFoos()
,@Cacheable
方法。但是...
通常,您可以使用适当的设计模式通过适当地(重新)构造代码来解决这类问题。这也不是唯一的解决方案。关于 Spring 的美丽之处在于,它为您提供了许多选择。这只是一种选择。
希望这可以为您提供更多建议。
答案 1 :(得分:-1)
使用密钥对对象进行缓存,因此在从缓存中检索时,可以使用该密钥。
@Override
@Cacheable(value = "fooByIDCache", key = "#id", unless = "#result == null")
public FooDto getFooByID(String id, FooDto fooDTO) {
return fooDTO;
}