At a current project we added some caches to our application to improve performance. However, we faced some issues I looked into and this article will demonstrate you should use caches with great precaution.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.pelssers</groupId> | |
<artifactId>cachingdemo</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<properties> | |
<spring.version>3.1.2.RELEASE</spring.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>cglib</groupId> | |
<artifactId>cglib-nodep</artifactId> | |
<version>2.2</version> | |
<scope>compile</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-core</artifactId> | |
<version>${spring.version}</version> | |
<scope>compile</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-beans</artifactId> | |
<version>${spring.version}</version> | |
<scope>compile</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-context</artifactId> | |
<version>${spring.version}</version> | |
<scope>compile</scope> | |
</dependency> | |
<dependency> | |
<groupId>net.sf.ehcache</groupId> | |
<artifactId>ehcache-core</artifactId> | |
<version>2.4.3</version> | |
<scope>compile</scope> | |
</dependency> | |
<dependency> | |
<groupId>com.google.guava</groupId> | |
<artifactId>guava</artifactId> | |
<version>14.0.1</version> | |
</dependency> | |
</dependencies> | |
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.pelssers.services; | |
import java.util.List; | |
public interface PricingService { | |
List<Integer> getPriceHistory(Long productId); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.pelssers.services; | |
import java.util.List; | |
import org.springframework.cache.annotation.Cacheable; | |
import com.google.common.collect.Lists; | |
public class PricingServiceImpl implements PricingService { | |
@Cacheable(value = "services.pricing", key = "#productId") | |
public List<Integer> getPriceHistory(Long productId) { | |
System.out.println("Fetching prices from DB"); | |
return Lists.newArrayList(2, 6, 8, 5, 9); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.pelssers.configuration; | |
import org.springframework.cache.CacheManager; | |
import org.springframework.cache.annotation.EnableCaching; | |
import org.springframework.cache.ehcache.EhCacheCacheManager; | |
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.core.io.ClassPathResource; | |
import com.pelssers.services.PricingService; | |
import com.pelssers.services.PricingServiceImpl; | |
@Configuration | |
@EnableCaching | |
public class DemoConfiguration { | |
@Bean | |
public PricingService pricingService() { | |
return new PricingServiceImpl(); | |
} | |
@Bean | |
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() { | |
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean(); | |
ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml")); | |
return ehCacheManagerFactoryBean; | |
} | |
@Bean | |
public CacheManager cacheManager() { | |
EhCacheCacheManager cacheManager = new EhCacheCacheManager(); | |
cacheManager.setCacheManager(ehCacheManagerFactoryBean().getObject()); | |
return cacheManager; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.pelssers.demo; | |
import java.util.Collections; | |
import java.util.List; | |
import org.springframework.context.ApplicationContext; | |
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | |
import org.springframework.stereotype.Component; | |
import com.pelssers.configuration.DemoConfiguration; | |
import com.pelssers.services.PricingService; | |
@Component | |
public class Main { | |
/** | |
* @param args | |
*/ | |
public static void main(String[] args) { | |
ApplicationContext context = new AnnotationConfigApplicationContext(DemoConfiguration.class); | |
PricingService pricingService = context.getBean(PricingService.class); | |
List<Integer> prices1 = pricingService.getPriceHistory(1L); | |
System.out.println(prices1); | |
Collections.reverse(prices1); | |
List<Integer> prices2 = pricingService.getPriceHistory(1L); | |
System.out.println(prices2); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ehcache> | |
<diskStore path="java.io.tmpdir" /> | |
<defaultCache | |
maxElementsInMemory="10000" | |
eternal="false" | |
timeToIdleSeconds="300" | |
timeToLiveSeconds="600" | |
overflowToDisk="true" | |
maxElementsOnDisk="10000000" | |
diskPersistent="true" | |
diskExpiryThreadIntervalSeconds="120" | |
memoryStoreEvictionPolicy="LRU" | |
statistics="true" /> | |
<cache | |
name="services.pricing" | |
maxElementsInMemory="1000" | |
eternal="false" | |
overflowToDisk="false" | |
timeToIdleSeconds="3600" | |
timeToLiveSeconds="7200" | |
memoryStoreEvictionPolicy="LFU" | |
transactionalMode="off" | |
statistics="true" /> | |
</ehcache> | |
<!-- running Main will result in following output. | |
Fetching prices from DB | |
[2, 6, 8, 5, 9] | |
[9, 5, 8, 6, 2] | |
What do we see here... we only fetch the list of prices the first time. | |
The second time we get back the cached value. | |
BUT we actually modified the list of prices (even in our cache). Potential PITFALL !! | |
--> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ehcache> | |
<diskStore path="java.io.tmpdir" /> | |
<defaultCache | |
maxElementsInMemory="10000" | |
eternal="false" | |
timeToIdleSeconds="300" | |
timeToLiveSeconds="600" | |
overflowToDisk="true" | |
maxElementsOnDisk="10000000" | |
diskPersistent="true" | |
diskExpiryThreadIntervalSeconds="120" | |
memoryStoreEvictionPolicy="LRU" | |
statistics="true" /> | |
<cache | |
name="services.pricing" | |
maxElementsInMemory="1000" | |
eternal="false" | |
overflowToDisk="false" | |
timeToIdleSeconds="3600" | |
timeToLiveSeconds="7200" | |
memoryStoreEvictionPolicy="LFU" | |
transactionalMode="off" | |
statistics="true" copyOnWrite="true" | |
copyOnRead="true" /> | |
</ehcache> | |
<!-- running Main will result in following output. | |
Fetching prices from DB | |
[2, 6, 8, 5, 9] | |
[2, 6, 8, 5, 9] | |
What do we see here... we only fetch the list of prices the first time. | |
The second time we get back the cached value. And even although we reversed | |
the prices the first time it has NO effect on our cached value. | |
This is in most situations what you want. | |
--> |
No comments:
Post a Comment