Hibernate SpringEhcache只有在同一请求中调用该方法时才能工作
我试图缓存我的结果,但每次对页面的调用(刷新)都会命中数据库。谢谢你的帮助 控制器Hibernate SpringEhcache只有在同一请求中调用该方法时才能工作,hibernate,spring-mvc,spring-data,ehcache,Hibernate,Spring Mvc,Spring Data,Ehcache,我试图缓存我的结果,但每次对页面的调用(刷新)都会命中数据库。谢谢你的帮助 控制器 showPage(){ MyPage<PhoneInfo> myPage = (MyPage<PhoneInfo>) phoneInfoService.findAllByOption(options, new MyPage<PhoneInfo>(page.intValue(), size.intValue())); //further experiment..
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()));
}
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);
}
Cacheable(value=“myPageCache”,key=“{#options,#pageable}”)
公共MyPagefindAllByOption(电话选项,MyPage可分页){
MyPage MyPage=phoneinforpoimpl.findAll(选项,可分页);
setTotalRows(_phoneInfoService.getCount(选项,可分页));
返回myPage;
}
@可缓存(value=“myPageCache”,key=“#选项”)
public int getCount(电话选项,MyPage可分页){
返回phoneInfoRepoImpl.getCount(选项,可分页);
}
更新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
}
@测试
公共void test1(){
PhoneOption options=新的PhoneOption();
选项。设置名称(“239”);
期权。设定状态(“1”);
MyPage MyPage=phoneInfoService.findAllByOption(选项,new MyPage());//点击数据库,确定
myPage=phoneInfoService.findAllByOption(选项,new myPage());//跳过数据库,确定
myPage=phoneInfoService.findAllByOption(选项,新建myPage(2,20));//点击数据库,当myPage更改时确定
}
@试验
公共无效测试2(){
PhoneOption options=新的PhoneOption();
选项。设置名称(“239”);
期权。设定状态(“1”);
MyPage MyPage=phoneInfoService.findAllByOption(选项,new MyPage());//这些选项与Test1完全相同,跳过数据库,OK!
myPage=phoneInfoService.findAllByOption(选项,new myPage());//跳过数据库,确定
myPage=phoneInfoService.findAllByOption(选项,新建myPage(2,20));//跳过数据库,确定
}
更新3在所有测试对象中实现hashCode和equals
现在在单元测试中,它一直都会命中db!因此,行为恶化了。
hashcode对于equal/same对象是相同的,equals工作正常,对于具有类似属性的对象返回true。您的键
“{#options,#pageable}”
每次都会有新值,即使您在这些对象中传递相同的值集,因为它们在每次页面刷新后都是全新的对象。因此,它们在每次第一次调用时都会被缓存。为了避免这种情况,您需要更改键。请尝试使用对象内的字段,如#object.field
组成键的元素需要定义适当的等于和hashcode
,这样即使您最终得到不同的实例,相等的值将导致正确的缓存命中。假设您已将@Cacheable注释放置在findAllByOption方法上,则它是否从缓存中拾取取决于您传递的参数。如果每次页面刷新都是相同的,那么肯定是从缓存中获取的。此外,缓存的生存时间为86400ms。你的页面刷新调用的频率是多少?嗨@Rakesh,是的,我在方法上有缓存。刷新期间传递的参数完全相同,每次页面刷新都是相同的,而不是从缓存中获取。对于测试,我将在几秒钟内刷新页面。。我明白了,尽管您在options对象中可能有相同的值,但由于它始终是一个具有不同hashkey的新对象,所以它不会像您期望的那样工作。您需要有不同的密钥生成策略。您可以尝试类似#options.field1+#options.field2…My options是一个包含大量字段(如id、类型、列表等)的类,任何或所有字段都可以为空。在这种情况下,如何生成密钥?已尝试#options.id+#options.code,但两者都为null,引发错误类型为“null”和“null”的对象之间不支持运算符“ADD”混合options.hashCode()中的所有字段是否有意义?这样行吗?然后我可以使用#选项作为键入服务方法吗?理想情况下,如果是这种情况,您不应该缓存您的结果,因为可以有多个组合,但如果您有一组固定的必填字段,请使用它们来形成键。是的,选项实际上是一组搜索选项,因此结果可能会非常不同;该应用程序灵活而健壮,对许多用户来说速度很慢,认为缓存会非常有益。必填字段集必须是唯一的,因为它是键,对吗?我的场景有更好的替代方案吗?为什么我说不应该在场景中缓存,因为存在多个组合,对于每个组合,您的输出都将被缓存,并且缓存大小可能很容易达到它的限制。正如您所说的,它与搜索相关,Elasticsearch可能是最合适的。实现了equals&hascode,行为更糟糕,总是命中缓存。。在更新中,我学习了hashcode和equals,它帮助我朝着正确的方向前进,所以谢谢。
@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
}