[英]Are Spring's cache annotations safe to use when evictions are involved?
I am using Spring 4.0.3, and utilizing the Cache Abstraction feature, backed by EhCache 2.8.1. 我正在使用Spring 4.0.3,并利用了EhCache 2.8.1支持的Cache Abstraction功能。
I was concerned that the method-level annotations @Cacheable
and @CacheEvict
may not properly lock the cache while editing it, resulting in thread safety problems. 我担心方法级注释@Cacheable
和@CacheEvict
在编辑高速缓存时可能无法正确锁定高速缓存,从而导致线程安全问题。 My test below seems to confirm that. 我在下面的测试似乎证实了这一点。 My question is, am I misusing the framework or misinterpreting the results of my test? 我的问题是,我是滥用框架还是误解了测试结果? Or am I correct in concluding that the annotations do not cause the cache to be properly locked, and therefore the use of @CacheEvict
does not guarantee that future reads will be valid? 还是我得出的结论是,批注不会导致缓存被正确锁定,因此是否正确,因此使用@CacheEvict
不能保证将来的读取将是有效的?
Test: 测试:
Create a database table to store a counter value 创建数据库表以存储计数器值
create table counter
(
counter integer
);
insert into counter values(0);
Create an entry in ehcache.xml to cache the counter value 在ehcache.xml中创建一个条目以缓存计数器值
<cache name="counter"
eternal="true"
maxElementsInMemory="1"/>
Create two request mapping methods in a Spring controller -- one to read the value of the counter and return after a long delay, and the other to increment the value and then return quickly 在Spring控制器中创建两种请求映射方法-一种读取计数器的值并在长时间延迟后返回,另一种递增该值然后快速返回
@RequestMapping("/viewcounter")
@ResponseBody
@Cacheable(value = "counter", key = "1")
public int readCounter() {
int count = dao.selectInteger("select counter from counter");
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
return count;
}
@RequestMapping("/incrementcounter")
@ResponseBody
@CacheEvict(value = "counter", key = "1")
public int incrementCounter() {
dao.update("update counter set counter = counter + 1");
int count = dao.selectInteger("select counter from counter");
return count;
}
Follow these three steps under two different scenarios -- first with the cache annotations removed from the controller methods, and then with them added back in 在两种不同的情况下执行以下三个步骤-首先从控制器方法中删除缓存注释,然后再将其添加回
/incrementcounter
造访/incrementcounter
/viewcounter
, and then immediately after initiating this request, visit /incrementcounter
in another tab 在一个浏览器选项卡中,访问/viewcounter
,然后在发起此请求后立即在另一个选项卡中访问/incrementcounter
/viewcounter
造访/viewcounter
Test results 检测结果
Expected result: 2
Actual result without caching: 2
Actual result with caching: 1
The with-caching result is wrong, yes? 缓存结果是错误的,是吗?
There's no locking in the cache abstraction. 缓存抽象中没有锁定。 You are not the first one asking for it and we already had significant brainstorming internally of what it would cost to support it. 您不是第一个要求它的人 ,我们已经在内部进行了广泛的头脑风暴,以讨论支持它的成本。 It turns out that it is far from being simple and playing with locks in such abstraction may be very tricky, especially in a "generic" way. 事实证明,它远非简单,以这种抽象方式使用锁可能非常棘手,尤其是以“通用”方式。 Also, cache vendors spend a significant amount of resources to support these kind of use cases and there's a reason for that. 同样,缓存供应商花费大量资源来支持此类用例,这是有原因的。
My best guess at it for the moment is that if you want these features, you need your cache to be transactional. 目前,我最好的猜测是,如果您想要这些功能,则需要缓存进行事务处理。 There are some gotcha when using it with the abstraction though, check in particular SPR-11540 which is being worked on at the moment. 但是,将其与抽象配合使用时有些陷阱,请特别检查目前正在研究的SPR-11540 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.