Search code examples
javacachingcache2k

cache2k cachesource working with mysql as backend


i am using cache2k as cache for my java application.

I use a CacheSource for get and peek requests if a cache is not in the in-mermoy cache. But now i want to implement the put method.

  1. How can i limit the memory cache to e.g. 1000 items (optional: with time to live)?
  2. How can i put an item into memory and into mysql? Just add a put method to cachesource? (MySQL is the persistent cache)

Hopefully somebody can help me.

private static Cache<String, Integer> c =
          CacheBuilder.newCache(String.class, Integer.class)
            .source(new CacheSource<String, Integer>() {
              public Integer get(String o) {
                System.out.println("ACCESSING SOURCE");
                return checkCache(o) ? 1: 0; // checkCache checks if the item is in MySQL Cache
              }
            })
            .name("cache")
            .build();

Solution

  • For the first question, you need to add two lines:

     private static Cache<String, Integer> c =
       CacheBuilder.newCache(String.class, Integer.class)
         .name("cache")
         .maxSize(1000) // limits in memory cache to 1000 entries
         .expirySecs(60) // sets expiry (time to live) to 60 seconds
         .source(new CacheSource<String, Integer>() {
           public Integer get(String o) {
             System.out.println("ACCESSING SOURCE");
             return checkCache(o) ? 1: 0;
           }
         })
        .build();
    

    Two hints on expirySecs: By default cache2k has a default expiry of 10 minutes. You can switch expiry off with expirySecs(-1). Upcoming cache2k version 0.20 will cleanup the interface: eternal(true) will switch expiry off. And expiryDuration(long, Timeunit) is the new method to set the expiry time. The methods expiryMillis and expirySecs are still present and supported, but will disappear in later releases.

    The second question: To put an entry into your cache with attached mysql persistence, please use this pattern:

     start database transaction
     update item in the database
     cache.remove(item key)
     commit the transaction
    

    The next cache access via get() will be a miss, invoke the cache source and fetch the updated element from the database. If a get() happens between remove() and database commit it will stall until the transaction is committed (this depends actually on your mysql settings and transaction isolation level). This pattern also works if you want to use cache2k as a cache for a database persistence layer.

    Using cache.put and then insert the element to the database leads to concurrency issues, since the two operations are not atomic. The above pattern is safer, but slower, since for each cache update a database store and fetch is needed.

    Another hint: The "best way" to do this will change in the future. I am adding general persistence support to cache2k at the moment. So it will be just a matter of adding the database properties in the future.