a Simple iBatis Cache using OSCache
Some values in a database are know to change slower than others. To improve performance, many developers like to cache often-used data to avoid making unnecessary trips back to the database. iBATIS provides its own caching system, that you configure through a <cacheModel> element.
The results from a query Mapped Statement can be cached simply by specifying the cacheModel parameter. A cache model is a configured cache that is defined within your DataMapper configuration file. IBATIS cache focuses on caching results within the persistence layer. As such, it is independent of the service or presentation layers, and is not based on object identity.
In this simple example, i’m using OSCache. OSCache is a robust caching framework that is able to perform many of the same type of caching strategies that iBATIS provides in its other cache models. When using the OSCACHE model, you create a dependency on the OSCache JARs. You will need to include the OSCache JAR in your project when you use this setting. This cache is configured in the same manner as a standard OSCache install. This means that you will need to have an oscache.properties file available on the root of your classpath for OSCache to read.
Okay, here’s my code,
a simple “test” database, and a “contoh” table
CREATE DATABASE 'test' USE 'test' CREATE TABLE `contoh` ( `nama` varchar(30) NOT NULL DEFAULT '', `alamat` varchar(100) DEFAULT NULL, PRIMARY KEY (`nama`) ) insert into contoh (nama, alamat) values ('edwin', 'jakarta'); insert into contoh (nama, alamat) values ('kamplenk', 'ciledug'); insert into contoh (nama, alamat) values ('nugie', 'pamulang'); insert into contoh (nama, alamat) values ('samsu', 'dago'); insert into contoh (nama, alamat) values ('tebek', 'jayapura');
a contoh POJO
package com.edw.bean; /** * * @author edw */ public class Contoh { private String nama; private String alamat; // other setter and getter }
and my sqlmapconfig.xml as my ibatis xml configuration
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <settings useStatementNamespaces="true" lazyLoadingEnabled="true" enhancementEnabled="true" maxSessions="20" /> <transactionManager type="JDBC" commitRequired="false"> <dataSource type="SIMPLE"> <property name="SetAutoCommitAllowed" value="false"/> <property name="DefaultAutoCommit" value="false"/> <property name="JDBC.Driver" value="com.mysql.jdbc.Driver"/> <property name="JDBC.ConnectionURL" value="jdbc:mysql://localhost/test"/> <property name="JDBC.Username" value="root"/> <property name="JDBC.Password" value="xxx"/> </dataSource> </transactionManager> <sqlMap resource="com/edw/sqlmap/contoh.xml"/> </sqlMapConfig>
and my xml query, at line 5 to 9 is my OSCache caching, and at line 21 is cacheModel implementation on query “selectAllContoh”. It means that i’m storing “selectAllContoh” resultSet on a cache, so the next time query “selectAllContoh” is called, iBatis will get resultSet from my cache instead of hitting my database.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" > <sqlMap namespace="contoh" > <cacheModel id="contohCache" type="OSCACHE"> <flushInterval hours="24"/> <flushOnExecute statement="contoh.insertContoh"/> <property name="reference-type" value="SOFT"/> </cacheModel> <resultMap id="result" class="com.edw.bean.Contoh"> <result property="nama" column="NAMA" columnIndex="1"/> <result property="alamat" column="ALAMAT" columnIndex="2"/> </resultMap> <insert id="insertContoh" parameterClass="com.edw.bean.Contoh" > insert into contoh (nama, alamat) values (#nama:VARCHAR#, #alamat:VARCHAR#) </insert> <select id="selectAllContoh" resultMap="result" cacheModel="contohCache"> select nama, alamat from contoh </select> </sqlMap>
a class to load my ibatis xml configuration
package com.edw.config; import com.ibatis.common.resources.Resources; import com.ibatis.sqlmap.client.SqlMapClient; import com.ibatis.sqlmap.client.SqlMapClientBuilder; import java.io.Reader; /** * * @author edw */ public class SqlMapConfig { protected static final SqlMapClient sqlMap; static { try { Reader reader = Resources.getResourceAsReader("com/edw/sqlmap/sqlmapconfig.xml"); sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader); } catch (Exception e){ throw new RuntimeException("Fatal Error. Cause: " + e, e); } } public static SqlMapClient getSqlMap() { return sqlMap; } }
and my log4j configuration, i named it 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 my oscache.properties
cache.capacity=1000
i create a simple JUnit class to test my class
package com.edw.test; import com.edw.bean.Contoh; import com.edw.config.SqlMapConfig; import java.util.List; import org.apache.log4j.Logger; import org.junit.Test; import static org.junit.Assert.*; /** * * @author edw */ public class TestIbatisCaching { @Test public void testIbatisCaching() { Logger logger = Logger.getLogger(this.getClass()); try { // repeated queries for (int i = 0; i < 5; i++) { List<Contoh> contohs = SqlMapConfig.getSqlMap().queryForList("contoh.selectAllContoh"); // check if it's null assertNotNull(contohs); //sleep Object o = new Object(); synchronized(o){ o.wait(2000); } for (Contoh contoh : contohs) { logger.debug(contoh.getNama()); } logger.debug("================================"); } } catch (Exception ex) { logger.error(ex); } } }
this is what happen on my console,
on line 24-25 shows how OSCache creating a cache from a query “contoh.selectAllContoh”,
and on line 37-38 shows how query “contoh.selectAllContoh” hitting Ibatis’ cache instead of the database.
2010-10-09 18:49:24,961 [Config] DEBUG com.opensymphony.oscache.base.Config:61 - OSCache: Config called 2010-10-09 18:49:24,968 [Config] INFO com.opensymphony.oscache.base.Config:147 - OSCache: Properties read {cache.capacity=1000} 2010-10-09 18:49:24,969 [AbstractCacheAdministrator] DEBUG com.opensymphony.oscache.base.AbstractCacheAdministrator:160 - Constructed AbstractCacheAdministrator() 2010-10-09 18:49:24,993 [GeneralCacheAdministrator] INFO com.opensymphony.oscache.general.GeneralCacheAdministrator:98 - Constructed GeneralCacheAdministrator() 2010-10-09 18:49:24,993 [GeneralCacheAdministrator] INFO com.opensymphony.oscache.general.GeneralCacheAdministrator:301 - Creating new cache 2010-10-09 18:49:25,028 [AbstractConcurrentReadCache] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:694 - get called (key=1542486422|5257123254|contoh.selectAllContoh|1339823102| select nama, alamat from contoh |executeQueryForList|0|-999999) 2010-10-09 18:49:25,028 [AbstractConcurrentReadCache] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:1061 - persistRetrieve called (key=1542486422|5257123254|contoh.selectAllContoh|1339823102| select nama, alamat from contoh |executeQueryForList|0|-999999) 2010-10-09 18:49:25,099 [Cache] DEBUG com.opensymphony.oscache.base.Cache:697 - No cache entry exists for key='1542486422|5257123254|contoh.selectAllContoh|1339823102| select nama, alamat from contoh |executeQueryForList|0|-999999', creating 2010-10-09 18:49:25,106 [CacheModel] DEBUG com.ibatis.sqlmap.engine.cache.CacheModel:27 - Cache 'contoh.contohCache': cache miss 2010-10-09 18:49:25,331 [SimpleDataSource] DEBUG com.ibatis.common.jdbc.SimpleDataSource:27 - Created connection 5230193. 2010-10-09 18:49:25,334 [Connection] DEBUG java.sql.Connection:27 - {conn-100000} Connection 2010-10-09 18:49:25,336 [Connection] DEBUG java.sql.Connection:27 - {conn-100000} Preparing Statement: select nama, alamat from contoh 2010-10-09 18:49:25,381 [PreparedStatement] DEBUG java.sql.PreparedStatement:27 - {pstm-100001} Executing Statement: select nama, alamat from contoh 2010-10-09 18:49:25,405 [PreparedStatement] DEBUG java.sql.PreparedStatement:27 - {pstm-100001} Parameters: [] 2010-10-09 18:49:25,406 [PreparedStatement] DEBUG java.sql.PreparedStatement:27 - {pstm-100001} Types: [] 2010-10-09 18:49:25,411 [ResultSet] DEBUG java.sql.ResultSet:27 - {rset-100002} ResultSet 2010-10-09 18:49:25,429 [ResultSet] DEBUG java.sql.ResultSet:27 - {rset-100002} Header: [NAMA, ALAMAT] 2010-10-09 18:49:25,429 [ResultSet] DEBUG java.sql.ResultSet:27 - {rset-100002} Result: [edwin, singapore] 2010-10-09 18:49:25,430 [ResultSet] DEBUG java.sql.ResultSet:27 - {rset-100002} Result: [kamplenk, ciledug] 2010-10-09 18:49:25,430 [ResultSet] DEBUG java.sql.ResultSet:27 - {rset-100002} Result: [nugie, pamulang] 2010-10-09 18:49:25,511 [ResultSet] DEBUG java.sql.ResultSet:27 - {rset-100002} Result: [samsu, dago] 2010-10-09 18:49:25,513 [ResultSet] DEBUG java.sql.ResultSet:27 - {rset-100002} Result: [tebek, jayapura] 2010-10-09 18:49:25,514 [AbstractConcurrentReadCache] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:694 - get called (key=1542486422|5257123254|contoh.selectAllContoh|1339823102| select nama, alamat from contoh |executeQueryForList|0|-999999) 2010-10-09 18:49:25,515 [AbstractConcurrentReadCache] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:1061 - persistRetrieve called (key=1542486422|5257123254|contoh.selectAllContoh|1339823102| select nama, alamat from contoh |executeQueryForList|0|-999999) 2010-10-09 18:49:25,519 [Cache] DEBUG com.opensymphony.oscache.base.Cache:697 - No cache entry exists for key='1542486422|5257123254|contoh.selectAllContoh|1339823102| select nama, alamat from contoh |executeQueryForList|0|-999999', creating 2010-10-09 18:49:25,520 [AbstractConcurrentReadCache] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:1108 - persistStore called (key=1542486422|5257123254|contoh.selectAllContoh|1339823102| select nama, alamat from contoh |executeQueryForList|0|-999999) 2010-10-09 18:49:25,521 [AbstractConcurrentReadCache] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:1087 - persistRetrieveGroup called (groupName=contoh.contohCache) 2010-10-09 18:49:25,521 [AbstractConcurrentReadCache] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:1127 - persistStoreGroup called (groupName=contoh.contohCache) 2010-10-09 18:49:25,523 [CacheModel] DEBUG com.ibatis.sqlmap.engine.cache.CacheModel:27 - Cache 'contoh.contohCache': stored object '[com.edw.bean.Contoh@12bb7e0, com.edw.bean.Contoh@134f69a, com.edw.bean.Contoh@2a15cd, com.edw.bean.Contoh@fd68b1, com.edw.bean.Contoh@e45076]' 2010-10-09 18:49:25,525 [SimpleDataSource] DEBUG com.ibatis.common.jdbc.SimpleDataSource:27 - Returned connection 5230193 to pool. 2010-10-09 18:49:27,526 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - edwin 2010-10-09 18:49:27,526 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - kamplenk 2010-10-09 18:49:27,526 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - nugie 2010-10-09 18:49:27,526 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - samsu 2010-10-09 18:49:27,526 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - tebek 2010-10-09 18:49:27,526 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:37 - ================================ 2010-10-09 18:49:27,536 [AbstractConcurrentReadCache] DEBUG com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache:694 - get called (key=1542486422|5257123254|contoh.selectAllContoh|1339823102| select nama, alamat from contoh |executeQueryForList|0|-999999) 2010-10-09 18:49:27,536 [CacheModel] DEBUG com.ibatis.sqlmap.engine.cache.CacheModel:27 - Cache 'contoh.contohCache': retrieved object '[com.edw.bean.Contoh@12bb7e0, com.edw.bean.Contoh@134f69a, com.edw.bean.Contoh@2a15cd, com.edw.bean.Contoh@fd68b1, com.edw.bean.Contoh@e45076]' 2010-10-09 18:49:29,536 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - edwin 2010-10-09 18:49:29,536 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - kamplenk 2010-10-09 18:49:29,536 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - nugie 2010-10-09 18:49:29,536 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - samsu 2010-10-09 18:49:29,536 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:34 - tebek 2010-10-09 18:49:29,536 [TestIbatisCaching] DEBUG com.edw.test.TestIbatisCaching:37 - ================================
this is my Netbeans project structure
Well, i guess it can help others. Thank you and see you again.
No Comments