我想从表中提取数据。table Name:学生
Student {
int id;
String Name;
};
我曾质问:
select Name from Student where id in (:ids);
需要:当我调用存储库student findByIdIn(:ids)时,我希望获得具有匹配id的学生,并缓存它们。如果我再次使用另一组id进行调用,则流程将如下所示:首先,它将检查该高速缓存中是否存在任何id数据,然后从缓存中获取这些数据,然后针对缓存中未获得的id进行DB调用,然后将其存储在缓存中。
期望 Spring Boot 缓存相关信息达到上述要求。
1条答案
按热度按时间e0bqpujr1#
这个问题的简短答案是否定的。
如果我正确理解了您的问题(并进行了验证),那么您将看到类似以下场景的内容:
给定
Student
ID[ 2, 3, 4, 5, 6 ]
的查询,并假定Student
ID[ 2, 4, 6 ]
在该高速缓存中,但Student
ID[ 3, 5 ]
当前仅在数据库中,则您将查找类似于以下内容的内容:参见完整的测试类here。
Spring的Cache Abstraction是核心Spring框架的一部分,并且仅由Sping Boot 扩展(例如,带有自动配置和一些额外功能),它只是用缓存行为装饰或 Package 现有的和昂贵的服务方法或数据访问调用(使用AOP)。换句话说,它要么全有,要么全无。
简单地说,如果你有
@Cacheable
服务(或仓库/ DAO)方法,就像这样:然后,Spring的缓存安排相对于您的用例存在几个问题。
问题一:
首先,
findById(..)
服务方法要么全有,要么全无。参见问题2)该高速缓存中或不在高速缓存中。如果KEY在该高速缓存中,则整个
findById(..)
服务方法甚至不会被调用。如果KEY不在该高速缓存中,那么将调用
findById(..)
服务方法,但是在处理服务方法的过程中不再涉及“Students”Cache
,除非您自己显式地涉及缓存,正如我在上面演示的那样(但这是另一个问题...问题3)。注意:Spring的缓存行为大致等同于
Map.computeIfAbsent(:KEY, :Function<KEY, VALUE>)
。问题二:
默认情况下(参见doc),Spring的Cache Abstraction使用所有方法参数来生成一个键。当然,您可以自定义键的生成,但在这种情况下这对您没有帮助。
因此,通过调用
@Cacheable findByIds(:Set<Integer>):List<Student>
,实际缓存在“Students”Cache
中的内容如下:也就是说,将有一个缓存条目,其中整个ID集是KEY,值是整个结果集,或返回的学生列表。
相反,您可能希望在使用一组ID(例如
[1, 2, 3]
)进行查询时,将每个单独的Student
(对象/记录)单独存储该高速缓存中:Spring不支持这种开箱即用的方式,而是it is possible to achieve。
问题三:
正如您在上面的通用解决方案中所看到的,Spring的
Cache
接口是围绕现有缓存提供程序(实际)缓存实现的 Adapter,它只允许单键访问。这对于每个关键字来说可能是相当昂贵的调用,这取决于1)关键字查询的数量(例如,10对1000个关键字可能是相当大的差别)和2)该高速缓存拓扑(本地对客户端/服务器对WAN等)。
理想情况下,您可以将所有键传递给
Cache
GET操作,虽然Spring的Cache Abstraction通常不支持这种操作,但底层的缓存提供程序缓存实现通常支持这种操作。例如,在Hazelcast中,
Cache
实现是[Distributed]IMap
(取决于您的拓扑和配置),因此,在获取对“本机”缓存的访问权限时,您可以调用IMap.getAll(:Set<K>)
。然而,这也是非常特定和依赖于缓存提供程序的,因此在将应用程序耦合到底层缓存提供程序API时,必须小心,特别是在更改缓存提供程序时。但是,它确实允许您改进我上面介绍的通用解决方案。
结论:
总而言之,Spring的Cache Abstraction不允许你做你在这里要求的事情,但是,也许使用一个自定义的AOP方面,或者仅仅创建一个自定义的DAO Package 你的SD仓库,你可以达到类似的效果。
我将把它作为一个练习留给您,因为此UC中的里程因您的应用程序要求(尤其是性能要求)而有很大的不同。
祝你好运!