2016-12-29 50 views
1

我使用Spring Boot和Spring Cache。我有一个方法,给定ID的列表,返回与这些ID匹配的Food列表:如何使用“IN”运算符缓存数据库查询?

public List<Food> get(List<Integer> ids) { 
    return "select * from FOOD where FOOD_ID in ids"; // << pseudo-code 
} 

我要来缓存ID的结果。想象一下,我做的:

List<Food> foods = get(asList(1, 5, 7)); 

然后:

List<Food> foods = get(asList(1, 5)); 

我想Food ID为1和Food ID为5,从缓存中检索。可能吗?

我知道我可以做一个方法:

@Cacheable(key = "id") 
public Food getById(id){ 
    ... 
} 

和重复的ID列表,并调用它每一次,但在这种情况下,我不走IN SQL运营商的优势,对不对?谢谢。

+0

只是做 '回报ids.stream()地图(服务:: getById).collect(Collectors.toList() )'0 –

回答

1

Cacheable的关键属性需要一个SpEL表达式来计算缓存键。所以,你应该能够做到像

@Cacheable(key = "#ids.stream().map(b -> Integer.toString(b)).collect(Collectors.joining(","))) 

这就要求IDS总是在相同的顺序

https://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html#cache-annotations-cacheable-key

一个更好的选择是创建一个类来抚慰着你可以为你生成缓存键的ID,或某种实用类功能。


没有@Cacheable另一种可能的解决办法是注入高速缓存管理器到像类:

@Autowired 
private CacheManager cacheManager; 

然后,您可以通过名称检索缓存管理器食物缓存

Cache cache = cacheManager.getCache('cache name'); 

然后你可以调整你的方法来获取ID列表并手动添加并从缓存中获取值

cache.get(id); 
cache.put(id, food); 

您很可能仍然无法使用SQL IN子句,但您至少需要处理方法内部的迭代,而不是处处调用此方法,并尽可能利用缓存。

public List<Food> get(List<Integer> ids) { 
    List<Food> result = new ArrayList<>(); 

    for(Integer id : ids) { 
     // Attempt to fetch from cache 
     Food food = cache.get(id); 

     if (food == null) { 
      // Fetch from DB 
      cache.put(id, food); 
     } 

     result.add(food); 
    } 

    return result; 
} 

相关的Javadoc:

http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/cache/CacheManager.html

http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/cache/Cache.html

+0

谢谢。但在这种情况下,我的问题中的例子不起作用,因为在这两种情况下密钥都不相同。我想缓存每一个食物,而不是整个集合。 –

+0

好的,在这种情况下,如果你想使用'@ Cacheable',你只需要迭代调用,让你的方法获得一个id并返回一个结果。 – kgengler

+0

如果没有@Cacheable,可以注入CacheManager并使用缓存实例手动输入并获取缓存值 – kgengler