[Java] Ehcache – cache engine

In modern web applications scalability could be one of things that you have to take under consideration when you plan architecture and use of tools in your project. If you know that your application will be used by hundreds or even thousands of clients, your database will be very big and SQL/JDBC/ORM queries will be very tough for hard disk and CPU – consider using cache. Currently I have work with Memcached and Ehcache. While Memcached is written in C and works as a server, Ehcache is a pure java solution and could also work without need for standalone process. In this article I will show an example of using Ehcache.

Important: you must have following jars (or newer versions) in classpath:

ehcache-core-2.3.1.jar
ehcache-terracotta-2.3.1.jar
slf4j-api-1.5.11.jar
slf4j-jdk14-1.5.11.jar

Consider the simple example:

import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;

/**
 * Simple class that keeps article.
 */
class Article {
        public static final String CACHE_NAME = "articleCache";
        private Integer id;
        private String text;
        private String author;
        public Article(Integer id, String text, String author) {
                this.id = id;
                this.author = author;
                this.text = text;
        }
/** getters and setters are removed */
}

public class EhcacheTest {
        private final Cache cache;
        /**
         * dynamic cache configuration
         * without using an xml file.
         */
        public EhcacheTest() {
                CacheManager cacheManager = new CacheManager();
                cacheManager.addCache(Article.CACHE_NAME);
                cache = cacheManager.getCache(Article.CACHE_NAME);
                // let's configure your cache!
                CacheConfiguration cacheConfiguration = cache
                                .getCacheConfiguration();
                cacheConfiguration.setMaxElementsInMemory(100);
                // after 30 seconds of creating element
                // will be marked as removed
                cacheConfiguration.setTimeToLiveSeconds(30);
                // if nothing uses key - the element
                // will be marked as removed after 15 seconds
                cacheConfiguration.setTimeToIdleSeconds(15);
                // LRU = Last Recently Used - when 100 elements already
                // in cache - removed will be last recently used one.
                cacheConfiguration.setMemoryStoreEvictionPolicy("LRU");
        }
        /**
         * For need of example I assume that this
         * is very long database operation which
         * takes about 10 seconds ;)
         */
        private Article getArticleFromDB(Integer id) throws Exception {
                System.out.println("!!!DB: article " + id);
                TimeUnit.SECONDS.sleep(10);
                return new Article(id, "some ehcache text",
                                "author is codesmuggler");
        }
        /**
         * Function for getting article.
         * First checks if it is already in cache -
         * if not - gets it from database and
         * places in cache
         */
        public Article getArticle(Integer id) throws Exception {
                // class used for keeping element data
                Element element = null;
                // have you this an article in cache?
                if ((element = cache.get(id)) == null) {
                        // you don't have an article in cache,
                        // so you have to ask database
                        // for it
                        Article article = getArticleFromDB(id);
                        element = new Element(id, article);
                        cache.put(element);
                        return article;
                } else {
                        // you have an article in cache,
                        // so just return the value!
                        System.out.println("CACHE: article " + id);
                        return (Article) element.getObjectValue();
                }
        }

        public static void main(String[] args) throws Exception {
                EhcacheTest ehcacheTest = new EhcacheTest();
                int i = 0;
                Format formatter = new SimpleDateFormat("HH:mm:ss");
                while (i++ < 5) {
                        System.out.println("TRY: " + i + " TIME: "
                                        + formatter.format(new Date()));
                        Article art = ehcacheTest.getArticle(7);
                        System.out.println("GOT ARTICLE: " + art.getId()
                                        + " TIME: " + formatter.format(new Date()));
                        // sleep to allow cache to knock out an article key
                        TimeUnit.SECONDS.sleep(10);
                }
        }
}

An example prints:

TRY: 1 TIME: 22:20:20
!!!DB: article 7
GOT ARTICLE: 7 TIME: 22:20:30
TRY: 2 TIME: 22:20:40
CACHE: article 7
GOT ARTICLE: 7 TIME: 22:20:40
TRY: 3 TIME: 22:20:50
CACHE: article 7
GOT ARTICLE: 7 TIME: 22:20:50
TRY: 4 TIME: 22:21:00
!!!DB: article 7
GOT ARTICLE: 7 TIME: 22:21:10
TRY: 5 TIME: 22:21:20
CACHE: article 7
GOT ARTICLE: 7 TIME: 22:21:20

As you see on 5 tries database operation is executed only 2 times, which saves 30 seconds of database engine execution! Moreover, you can configure ehcache whatever you like. You may also use an XML file for it – but configuration options are the topic for another article.
Using cache for your application – if well configured – can cut off execution time of clients requests. However, in small applications can be an overkill.

This entry was posted in coding, enterprise edition, java and tagged , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*


*

You may use these HTML tags and attributes: