【发布时间】:2018-01-21 08:53:22
【问题描述】:
我正在尝试缓存我的结果,但是对页面的每次调用(刷新)都会命中数据库。任何帮助表示赞赏,谢谢。
控制器
showPage(){
MyPage<PhoneInfo> myPage = (MyPage<PhoneInfo>) phoneInfoService.findAllByOption(options, new MyPage<PhoneInfo>(page.intValue(), size.intValue()));
//further experiment.. below does not hit db
myPage = (MyPage<PhoneInfo>) phoneInfoService.findAllByOption(options, new MyPage<PhoneInfo>(page.intValue(), size.intValue()));
}
对服务方法的第二次调用没有进行 db 调用,这是正确的。 然而,页面刷新再次调用 showPage() 并且对服务的第一次调用再次命中 db。我希望它来自缓存。
我测试了 2 个单元测试,两个测试对服务方法的调用相同,测试 1 命中 db 而测试 2 跳过,这是正确的。测试中的多个服务调用也被跳过,这也是正确的。
规格
Spring 4.3.3.RELEASE、安全 4.2.3.RELEASE、Hibernate 5.2.8.Final、 Ehcache 2.10.4
缓存配置
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager(net.sf.ehcache.CacheManager cacheManager) {
return new EhCacheCacheManager(cacheManager);
}
@Bean
public EhCacheManagerFactoryBean ehCacheCacheManager() {
EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
cmfb.setShared(true);
return cmfb;
}
}
src/resources/ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true">
<diskStore path="java.io.tmpdir" />
<cache name="myPageCache" maxEntriesLocalHeap="1000" maxEntriesLocalDisk="10000" eternal="false" diskSpoolBufferSizeMB="20" timeToIdleSeconds="86400" timeToLiveSeconds="86400" overflowToDisk="false" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <persistence strategy="localTempSwap" /> </cache>
</ehcache>
更新 1 下面列出服务方法
Cacheable(value = "myPageCache", key = "{#options, #pageable}")
public MyPage<PhoneInfo>findAllByOption(PhoneOption options, MyPage<PhoneInfo> pageable){
MyPage<PhoneInfo> myPage = phoneInfoRepoImpl.findAll(options, pageable);
myPage.setTotalRows(_phoneInfoService.getCount(options, pageable));
return myPage;
}
@Cacheable(value = "myPageCache", key = "#options")
public int getCount(PhoneOption options, MyPage<PhoneInfo> pageable){
return phoneInfoRepoImpl.getCount(options, pageable);
}
更新 2 单元测试
@Test
public void test1(){
PhoneOption options = new PhoneOption();
options.setName("239");
options.setStatus('1');
MyPage<PhoneInfo> myPage = phoneInfoService.findAllByOption(options, new MyPage<PhoneInfo>()); //hits db, Ok
myPage = phoneInfoService.findAllByOption(options, new MyPage<PhoneInfo>()); //skips db, OK
myPage = phoneInfoService.findAllByOption(options, new MyPage<PhoneInfo>(2, 20)); //hits db, OK as MyPage changed
}
@Test
public void test2(){
PhoneOption options = new PhoneOption();
options.setName("239");
options.setStatus('1');
MyPage<PhoneInfo> myPage = phoneInfoService.findAllByOption(options, new MyPage<PhoneInfo>()); //these options exactly same as Test1, skips db, OK!
myPage = phoneInfoService.findAllByOption(options, new MyPage<PhoneInfo>()); //skips db, Ok
myPage = phoneInfoService.findAllByOption(options, new MyPage<PhoneInfo>(2, 20)); //skips db, Ok
}
更新 3在所有测试对象中实现 hashCode 和 equals
现在在单元测试中,它一直在命中 db!所以行为变差了。 对于相等/相同的对象,hashcode 相同,equals 也可以正常工作,对于具有相似属性的对象返回 true。
【问题讨论】:
-
假设您在 findAllByOption 方法上放置了@Cacheable 注解,那么它是否从缓存中选择取决于您传递的参数。如果它们对于每次页面刷新都相同,那么您肯定会从缓存中获取它。此外,您的缓存生存时间为 86400 毫秒。您的页面刷新调用频率是多少?
-
嗨@Rakesh,是的,我在该方法上有Cacheable。在刷新期间传递完全相同的参数,对于每次页面刷新都相同,而不是从缓存中获取。为了测试,我会在几秒钟内刷新页面..也会发布服务方法
-
我明白了,尽管您可能在选项对象中具有相同的值,但由于它始终是具有不同哈希键的新对象,它不会像您期望的那样工作。您需要有不同的密钥生成策略。
-
你可以试试#options.field1 + #options.field2 ...
标签: hibernate spring-mvc spring-data ehcache