MyBatis Caching Using OSCache
In this example im trying to create a simple application using MyBatis cache ability. What is cache anyway? A cache is designed to reduce traffic between your application and the database by conserving data already loaded from the database and put it whether in memory or in file. Database access is necessary only when retrieving data that is not currently available in the cache. So basically not all queries are taken from database, but from cache instead.
As you can see here, MyBatis has lots of caching products. But on this example im using OSCache.
First, as always, a simple mysql table
CREATE TABLE contoh ( nama VARCHAR(10) NOT NULL, alamat VARCHAR(200), PRIMARY KEY (nama) ) insert into contoh (nama, alamat) values ('edw', 'Jakarta'); insert into contoh (nama, alamat) values ('danu', 'Ciledug'); insert into contoh (nama, alamat) values ('kamplenk', 'Tangerang'); insert into contoh (nama, alamat) values ('tebek', 'BSD'); insert into contoh (nama, alamat) values ('nugie', 'Pamulang'); insert into contoh (nama, alamat) values ('samsu', 'Bandung');
And a simple java bean to represent my table,
package com.edw.bean; import java.io.Serializable; public class Contoh implements Serializable { private String nama; private String alamat; // setter and getter @Override public String toString(){ return nama+" : "+alamat; } }
And a simple java interface to create query method
package com.edw.mapper; import com.edw.bean.Contoh; import java.util.List; public interface ContohMapper { List<Contoh> selectAll(); }
My xml query, please take a look at line 5.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.edw.mapper.ContohMapper" > <cache type="org.mybatis.caches.oscache.OSCache"/> <resultMap id="ContohMap" type="com.edw.bean.Contoh" > <id column="nama" property="nama" jdbcType="VARCHAR" /> <result column="alamat" property="alamat" jdbcType="VARCHAR" /> </resultMap> <select id="selectAll" resultMap="ContohMap"> SELECT * FROM contoh </select> </mapper>
And my xml configuration to load all my xml queries,
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="UNPOOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost/test"/> <property name="username" value="root"/> <property name="password" value=""/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/edw/xml/ContohMapper.xml" /> </mappers> </configuration>
A java class to load all my xml configurations,
package com.edw.config; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MyBatisSqlSessionFactory { protected static final SqlSessionFactory FACTORY; static { try { Reader reader = Resources.getResourceAsReader("com/edw/xml/Configuration.xml"); FACTORY = new SqlSessionFactoryBuilder().build(reader); } catch (Exception e){ throw new RuntimeException("Fatal Error. Cause: " + e, e); } } public static SqlSessionFactory getSqlSessionFactory() { return FACTORY; } }
Now i create my main java class.
package com.edw.main; import com.edw.bean.Contoh; import com.edw.config.MyBatisSqlSessionFactory; import com.edw.mapper.ContohMapper; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.log4j.Logger; public class Main { private Logger logger = Logger.getLogger(this.getClass()); public Main(){ } private void execute(){ // test caching by doing select queries for 10 times for (int i = 0; i < 10; i++) { SqlSession session = MyBatisSqlSessionFactory.getSqlSessionFactory().openSession(); ContohMapper mapper = session.getMapper(ContohMapper.class); List<Contoh> contohs = mapper.selectAll(); for (Contoh contoh : contohs) { logger.debug(contoh); } session.close(); try { logger.debug("sleeping for 3 seconds"); Thread.sleep(3000); } catch (Exception e) { } } } public static void main(String[] args) { Main main = new Main(); main.execute(); } }
Last, is create 2 properties file. One is for log4j configuration, and another one for oscache configuration.
This is my log4j.properties
# Global logging configuration log4j.rootLogger=DEBUG,stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d [%c{1}] %-5p %c:%L - %m%n
And this is my oscache.properties
cache.capacity=1000 cache.memory=true cache.algorithm=com.opensymphony.oscache.base.algorithm.LRUCache
If you run the application, you’ll notice that for the second queries it will take from cache instead of database. This is what written on my log console.
2012-05-20 02:06:11,687 [Connection] DEBUG java.sql.Connection:27 - ooo Connection Opened 2012-05-20 02:06:11,688 [AbstractConcurrentReadCache] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:694 - get called (key=1247278887:1786588787:com.edw.mapper.ContohMapper.selectAll:0:2147483647:SELECT * FROM contoh) 2012-05-20 02:06:11,688 [LoggingCache] DEBUG org.apache.ibatis.cache.decorators.LoggingCache:27 - Cache Hit Ratio [com.edw.mapper.ContohMapper]: 0.6666666666666666 2012-05-20 02:06:11,689 [Main] DEBUG com.edw.main.Main:31 - edw : Jakarta 2012-05-20 02:06:11,689 [Main] DEBUG com.edw.main.Main:31 - danu : Ciledug 2012-05-20 02:06:11,692 [Main] DEBUG com.edw.main.Main:31 - kamplenk : Tangerang 2012-05-20 02:06:11,692 [Main] DEBUG com.edw.main.Main:31 - tebek : BSD 2012-05-20 02:06:11,692 [Main] DEBUG com.edw.main.Main:31 - nugie : Pamulang 2012-05-20 02:06:11,693 [Main] DEBUG com.edw.main.Main:31 - samsu : Bandung 2012-05-20 02:06:11,693 [Connection] DEBUG java.sql.Connection:27 - xxx Connection Closed 2012-05-20 02:06:11,693 [Main] DEBUG com.edw.main.Main:36 - sleeping for 3 seconds BUILD STOPPED (total time: 8 seconds)