Simple Spring Memcached – Spring Caching Abstraction and Memcached

Caching remains the one of the most basic performance enhancing mechanism in any read heavy database application. Spring 3.1 release came up with a cool new feature called Cache Abstraction. Spring Cache Abstraction provides the application developers an easy, transparent and decoupled way to implement any caching solution. Memcached is one of the most popular distributed caching system used across apps. In this post we will focus on how to integrate memcached with a Spring enabled applications. Since Spring directly supports only Ehcache and ConcurrentHashMap so we will fall down to a third party library Simple Spring Memcache to leverage power of spring caching abstraction.

Getting The Code

Code for this tutorial can be downloaded from following SVN location. https://www.assembla.com/code/weblog4j/subversion/nodes/24/SpringDemos/trunk For the tutorial to work please create the following table in your db. Then modify the datasource in springcache.xml.

CREATE  TABLE IF NOT EXISTS `adconnect`.`books` (
  `book_id` INT NOT NULL AUTO_INCREMENT ,
  `book_name` VARCHAR(500) NULL ,
  `book_author` VARCHAR(500) NULL ,
  `category` VARCHAR(500) NULL ,
  `numpages` INT NULL ,
  `price` FLOAT NULL ,
  PRIMARY KEY (`book_id`) )
ENGINE = InnoDB;

Integration Steps

1. Dependencies - I also assume that you have your hibernate, spring and logs set up. So for downloading SSM dependencies add following to your POM. For full set of dependencies please download the project from SVN url above.

<dependency>
     <groupId>com.google.code.simple-spring-memcached</groupId>
     <artifactId>spring-cache</artifactId>
     <version>3.1.0</version>
</dependency>

<dependency>
     <groupId>com.google.code.simple-spring-memcached</groupId>
     <artifactId>xmemcached-provider</artifactId>
     <version>3.1.0</version>
</dependency>

2. Enable Caching – To enable caching in your spring application add following to your spring context xml.

<cache:annotation-driven/>

3. Configure Spring to enable Memcached based caching  – Add following to your application context xml.

<bean name="cacheManager" class="com.google.code.ssm.spring.SSMCacheManager">
     <property name="caches">
         <set>
             <bean class="com.google.code.ssm.spring.SSMCache">
                 <constructor-arg name="cache" index="0" ref="defaultCache"/>
                 <!-- 5 minutes -->
                 <constructor-arg name="expiration" index="1" value="300"/>
                 <!-- @CacheEvict(..., "allEntries" = true) doesn't work -->
                 <constructor-arg name="allowClear" index="2" value="false"/>
             </bean>
         </set>
     </property>

    </bean>

<bean name="defaultCache" class="com.google.code.ssm.CacheFactory">
     <property name="cacheName" value="defaultCache"/>
     <property name="cacheClientFactory">
        <bean name="cacheClientFactory" class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl"/>
     </property>
     <property name="addressProvider">
         <bean class="com.google.code.ssm.config.DefaultAddressProvider">
            <property name="address" value="127.0.0.1:11211"/>
         </bean>
     </property>
     <property name="configuration">
         <bean class="com.google.code.ssm.providers.CacheConfiguration">
             <property name="consistentHashing" value="true"/>
         </bean>
     </property>

</bean>

SSMCacheManager extends org.springframework.cache.support.AbstractCacheManager – It is an  abstract class and is a manager for underlying Cache.

SSMCache implements org.springframework.cache.Cache – This is actual  wrapper round underlying cache client api.

4. Annotation Driven caching – Spring uses annotation to mark a method that it is to be managed by  cache.  These are the annotations defined by spring caching framework

  1. @Cacheable – This annotation is used to mark a method whose results are to be cached. If a cacheable method is called then spring first looks if result of the method is cached or not. If it present in cache then result is pulled from there else it the method call is made.                                                                                                                         
  2. @CachePut – Methods marked with cacheput annotations are always run and their results are pushed to cache. You should not place both Cacheput and Cacheable annotation on same method as they have different behaviour. Cacheput will result in method getting executed all the time while cacheable results in method getting executed only once.
  3. @CacheEvict – This annotation results in eviction of objects from the cache. This is generally used when the result object is updated hence the old object from cache needs to be purged.
  4. @Caching – This annotation is used if multiple annotations of same type is to be put on a method.

@Cacheable Demo 

@Cacheable(value = "defaultCache", key = "new Integer(#book_id).toString().concat('.BookVO')")
    public BookVO get(int book_id) throws Exception {
        BookVO bookVO = null;
		try{
			Query query = getSession().createQuery("from BookVO bookVO where bookVO.book_id=:book_id");
			query.setLong("book_id", book_id);
			bookVO =  (BookVO)query.uniqueResult();
		}catch(HibernateException he){
			log.error("Error in finding a bookVO : " + he);
            throw new Exception("Error in finding adPicVO by book_id for book_id : " + bookVO, he);
		}
		return bookVO;
    }

Please note the key attribute of the annotation. This is an example of Spring Expression Language. You can use SePL use to create memcache key according to your requirement. In this example I want a key which should be of form <book_id>.BookVO. 

Another Example – Lets say I want to store a list of bookVO from a given author in that case I can a unique key of form <author_name>.BookVOList so for that I can use following key

@Cacheable(value = "defaultCache", key = "#author.concat('.BookVOList')")
    public List<BookVO> getList(String author) throws Exception {

@CachePut Demo

@CachePut(value = "defaultCache", key = "new Integer(#bookVO.book_id).toString().concat('.BookVO')")
    public BookVO create(BookVO bookVO) throws Exception {
        try{
			getSession().save(bookVO);
			getSession().flush();
		}catch(HibernateException he){
			log.error("Error in inserting bookVO : " + he);
            throw new Exception("Error in inserting bookVO", he);
		}

		return bookVO;
    }

CachePut can be used while inserting data where data inserted can be put in cache after insertion is done

@CacheEvict Demo

@CacheEvict(value = "defaultCache", key = "new Integer(#bookVO.book_id).toString().concat('.BookVO')")
    public BookVO update(BookVO bookVO) throws Exception {
        try{
            Query query = getSession().createQuery("update BookVO bookVO set bookVO.book_name=:book_name, bookVO.book_author=:book_author,bookVO.category=:category,bookVO.numpages=:numpages,bookVO.price=:price " +
                                                   "where bookVO.book_id=:book_id");
            query.setString("book_name", bookVO.getBook_name());
            query.setString("book_author", bookVO.getBook_author());
            query.setString("category", bookVO.getCategory());
            query.setInteger("numpages", bookVO.getNumpages());
            query.setFloat("price", bookVO.getPrice());
			query.setLong("book_id", bookVO.getBook_id());
            query.executeUpdate();
		}catch(HibernateException he){
			log.error("Error in updating bookVO : " + he);
            throw new Exception("Error in updating bookVO", he);
		}

		return bookVO;
    }

References

  1. https://code.google.com/p/simple-spring-memcached/
  2. http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/cache.html
  3. http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/expressions.html
  4. http://static.springsource.org/spring/docs/3.1.0.M1/javadoc-api/index.html?org/springframework/cache/CacheManager.html
  5. http://doanduyhai.wordpress.com/2012/07/01/cache-abstraction-in-spring-3/
  6. http://viralpatel.net/blogs/cache-support-spring-3-1-m1/

That is all folks. I hope you enjoyed the post, don’t forget to post in some comments.

Warm Regards

Niraj

Print Friendly

About Niraj Singh

I am CEO and CoFounder of a startup "Aranin Software Private Limited, Bangalore. I completed my graduation in 2002 as an Aerospace Engineer from IIT Kharagpur. I love working on new ideas and projects and recently released my first open source project JaiomServer "http://jaiomserver.org". I have 9 years of experience in IT industries most of which I have spent in developing community applications for various clients using java. Some of the sites in which I have actively involved with are hgtv.com, food.com, foodnetwork.com, pickle.com, diynetwork.com etc.
This entry was posted in Caching, Memcached, Scalibility, Simple Spring Memcached, Spring Caching Abstraction and tagged , , , , , . Bookmark the permalink.

10 Responses to Simple Spring Memcached – Spring Caching Abstraction and Memcached

  1. Hello Mr Singh,

    Nice blog! Is there an email address I can contact you in private?

    Thanks,
    Eleftheria Kiourtzoglou

    Head of Editorial Team
    Java Code Geeks
    email: eleftheria[dot]kiourtzoglou[at]javacodegeeks[dot]com

  2. Niraj Singh says:

    Guys,

    Made some changes to the post. It is merely the table structure and related vo/dao that has been modified. The content remains the same.

    Regards
    Niraj

  3. itoctopus says:

    Hi Niraj,

    I wouldn’t use Memcached – it has so much problems it’s unbelievable. Custom made file system caching is much better and much more reliable when implemented intelligently.

    Thanks for sharing.
    itoctopus recently posted…Increasing the Search Limit in Joomla to More than 20 CharactersMy Profile

    • Niraj Singh says:

      Hi Itoctopus,

      Thanks for the comment. Can you be more specific with the problems you have faced? I can personally vouch for Memcached as it has helped in scaling few of the very high traffic sites I have worked on. Couple of the sites have had page views in excess of 1oo million per month. And the reason they take so much hits is because of memcached.

      Also it is publicly known that facebook, youtube, twitter, digg, wikipaedea etc use memcached.

      Warm Regards
      Niraj

  4. ananth says:

    The code is not working for me. I’ve created a method with @Cachable annotation and with memcached up, the method is getting called again and again. !!!!!!!
    ananth recently posted…Hadoop MapReduce – Best PracticesMy Profile

    • Niraj Singh says:

      Hi Ananth,

      Thanks for the comment. There are few things to check.
      1. Your spring version > 3.1
      2. If you are using code as is then check the location of log4j.properties and springcache.xml in SpringMemcachedDemo.
      3. Check the database connectivity params in datasource bean in springcache.xml.

      If you have created the new method then please share the code of method along with cacheable annotation.

      Regards
      Niraj

  5. davidxu says:

    nice job,help me a lot.ths!

Leave a Reply

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

Connect with Facebook

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

CommentLuv badge