cache Posts

Creating a Simple Spring Boot @Cacheable Cache using JBoss DataGrid on top of Openshift

Creating a Simple Spring Boot @Cacheable Cache using JBoss DataGrid on top of Openshift

Several days ago, one of my team member were asking me on how to connect Spring Boot to JBoss Datagrid as its primary cache server. Since we are using Openshift, im using Openshift template “Red Hat JBoss Data Grid 7.2 (Ephemeral, no https)” as base image deployment.

First we need to create instance of Datagrid on Openshift,

Create our cache name,

And finally, we can see our JBoss Datagrid endpoint here, and fyi we are using HotRod protocol to connect to JDG so our endpoint name should be “jdg-datagrid-app-01-hotrod” with port “11333”.

And start our project by creating a pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.edw</groupId>
    <artifactId>TestingJDGCacheable</artifactId>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>



        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-client-hotrod</artifactId>
            <version>8.4.0.Final-redhat-2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


    </dependencies>

    <profiles>
        <profile>
            <id>openshift</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>io.fabric8</groupId>
                        <artifactId>fabric8-maven-plugin</artifactId>
                        <version>3.5.28</version>
                        <executions>
                            <execution>
                                <id>fmp</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>resource</goal>
                                    <goal>build</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <generator>
                                <config>
                                    <spring-boot>
                                        <fromMode>isTag</fromMode>
                                        <from>redhat-openjdk18-openshift:1.2</from>
                                    </spring-boot>
                                </config>
                            </generator>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

    <repositories>
        <repository>
            <id>jboss</id>
            <url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>redhat-techpreview</id>
            <name>Red Hat Tech Preview</name>
            <url>https://maven.repository.redhat.com/techpreview/all/</url>
            <layout>default</layout>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>redhat-ga</id>
            <name>Red Hat GA</name>
            <url>https://maven.repository.redhat.com/ga/</url>
            <layout>default</layout>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>jboss-plugins</id>
            <url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>redhat-techpreview</id>
            <url>https://maven.repository.redhat.com/techpreview/all/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>redhat-ga</id>
            <url>https://maven.repository.redhat.com/ga/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

After that, we can create our Spring Boot project, and start with a main java class,

@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Register your JBoss Datagrid cache

@Configuration
public class CacheConfig {
    @Bean
    public RemoteCacheManager remoteCacheManager() {
        ConfigurationBuilder builder = new ConfigurationBuilder();
        builder.addServers("jdg-datagrid-app-01-hotrod:11333");
        return new RemoteCacheManager(builder.build());
    }
}

And a simple controller where our cache will be used, as on below code we are using “bakerooo” cache.

@RestController
public class IndexController {
    @GetMapping("/")
    @Cacheable("bakerooo")
    public Long getNow() {
        return System.currentTimeMillis();
    }
}

We can deploy our code by using maven’s fabric8 plugin,

mvn clean package fabric8:deploy

And test it by using a simple curl command.
Feel free to ask question, and you can download the full code at my github repo here.

Google+

[Java] Cara Cache Data Hasil Query dengan SpringMVC

Pada tulisan kali ini, saya coba membuat suatu metode caching untuk menyimpan data-data master kedalam memory, sehingga tidak perlu query ke database lagi. Hal ini cocok digunakan untuk menyimpan data-data master yang sangat jarang berubah, seperti kode provinsi ataupun kode cabang.

Okay, di tutorial ini saya menggunakan Spring MVC 4, Hibernate dan ehCache sebagai cache provider. Berikut adalah pom.xml yang digunakan,

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edw</groupId>
    <artifactId>mavenproject5</artifactId>
    <version>1</version>
    <packaging>war</packaging>

    <name>mavenproject5</name>

    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        
        
        <!-- Spring 4 dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.1.2.RELEASE</version>
         </dependency>
         
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        
        
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.2.2</version>
        </dependency>
        
        <!--ehcache-->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>
        
        <!--hibernate-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.8.Final</version>
        </dependency>
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${endorsed.dir}</outputDirectory>
                            <silent>true</silent>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>javax</groupId>
                                    <artifactId>javaee-endorsed-api</artifactId>
                                    <version>7.0</version>
                                    <type>jar</type>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

Kemudian konfigurasi standard yang digunakan di SpringMVC, applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

    <context:annotation-config/>
    
    <tx:annotation-driven/>
    
    <cache:annotation-driven />
    
    <context:component-scan base-package="com.edw.mavenproject5.service"/>
    
     <!-- datasource  -->
    <bean id="ds" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close"
          p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost/test"
          p:username="root" p:password=""
          p:initialSize="10"
          p:maxActive="50"
          p:maxIdle="10"
          p:minIdle="3"
          p:maxWait="30000"
          p:removeAbandoned="true"
          p:removeAbandonedTimeout="30"
          p:validationQuery="SELECT 1" />
    
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
        p:dataSource-ref="ds" p:configLocations="classpath:hibernate.cfg.xml" depends-on="ds">
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=org.hibernate.dialect.MySQLDialect
                hibernate.query.substitutions=true
                hibernate.show_sql=true
                hibernate.enable_lazy_load_no_trans=true
            </value>
        </property>
    </bean> 
    
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
    <bean id="cacheManager" 
          class="org.springframework.cache.ehcache.EhCacheCacheManager" 
          p:cache-manager-ref="ehcache"/>
    <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
          p:config-location="classpath:ehcache.xml"/>
    
</beans>

dan dispatcher-servlet.xml,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">


    <context:component-scan base-package="com.edw.mavenproject5.controller" />
	
    <mvc:annotation-driven />
    <mvc:default-servlet-handler />

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />
</beans>

yang kemudian dipanggil dari web.xml,

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

Nah, ada satu konfigurasi xml yang penting dalam membuat cache. Yaitu ehcache.xml, disana disimpan nama cache serta lama waktu hidupnya

<?xml version="1.0" encoding="UTF-8"?>
<!--
    caching configuration
-->
<ehcache>
    
    <defaultCache
        maxElementsInMemory="5000"
        eternal="true"
        overflowToDisk="false"
        memoryStoreEvictionPolicy="LRU"
    />
    
    <!--2menit-->
    <cache name="duaMenit"
           maxElementsInMemory="10000"
           timeToLiveSeconds="120"
           memoryStoreEvictionPolicy="LRU" 
    />
    
    <!--1menit-->
    <cache name="satuMenit"
           maxElementsInMemory="10000"
           timeToLiveSeconds="60"
           memoryStoreEvictionPolicy="LRU" 
    />
</ehcache>

Nah sekarang kita buat class java-nya, dimulai dari service layer. Perhatikan annotation Cacheable, konfigurasi tersebut adalah konfigurasi yang menandakan lokasi method yang kita cache.

package com.edw.mavenproject5.service;

import com.edw.mavenproject5.bean.Dosen;
import java.util.List;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class DosenService {

    @Autowired
    private SessionFactory sessionFactory;
    
    @Cacheable(key = "#root.methodName", value = "duaMenit")
    public List<Dosen> getDosens() {
        return sessionFactory.getCurrentSession().createCriteria(Dosen.class).list();
    }
    
    @Cacheable(key = "#root.methodName + #idDosen", value = "satuMenit")
    public Dosen getDosen(String idDosen) {
        return (Dosen) sessionFactory.getCurrentSession().get(Dosen.class, idDosen);
    }
    
}

Yang kemudian dipanggil dari controller,

package com.edw.mavenproject5.controller;

import com.edw.mavenproject5.service.DosenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class IndexController {
    
    @Autowired
    private DosenService dosenService;
    
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index(ModelMap modelMap){
        modelMap.put("dosens", dosenService.getDosens());
        return "index";
    }
    
    @RequestMapping(value = "/get", method = RequestMethod.GET)
    public String get(ModelMap modelMap, String id){
        modelMap.put("dosen", dosenService.getDosen(id));
        return "index";
    }
}

Dan berikut adalah ui yang digunakan untuk menampilkan hasil query didatabase,

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>Hello World!</h1>
        
        <c:if test="${not empty dosens}">
        <table class="table table-hover table-striped">
            <thead>
                <tr>
                    <th>ID Dosen</th>
                    <th>Nama Dosen</th>
                </tr>
            </thead>
            <tbody>
            <c:forEach items="${dosens}" var="dosen">
                <tr>
                    <td>${dosen.iddosen}</td>
                    <td>${dosen.namadosen}</td>
                </tr>
            </c:forEach>
            </tbody>
        </table>
        </c:if>
        
        <c:if test="${not empty dosen}">
            <h1>Hello Dosen ${dosen.namadosen}!</h1>
        </c:if>
    </body>
</html>

Hasil akhirnya adalah sebagai berikut, data dengan kode 02 dan 321 sudah diubah secara langsung didatabase, namun walaupun browser di-refresh berulang kali, tetap menampilkan data yang lama, yaitu “Dodol” dan “Testing 123 123”.
capture1

Untuk sourcecode lengkapnya bisa diunduh di github, https://github.com/edwinkun/CachingWithSpringMVC. (*)

Google+

A Simple MyBatis Caching using Redis

Mybatis recently introduce a new caching mechanism using Redis (http://mybatis.github.io/redis-cache/index.html), and in this tutorial i’m trying to create a simple demonstration for it. MyBatis’ Redis caching is a little bit different with other MyBatis’ caching provider, such as EhCache or OsCache because you need to install Redis server before using it.

Because Redis project does not officially support Windows and i need Redis to run as a windows service so im downloading redis-service.exe from this url (https://github.com/rgl/redis/downloads), install and run it. You can see Redis is running on port 6379.

Because MyBatis Redis Cache hasnt available on Maven repository, so next step is download MyBatis Redis Cache project from github (https://github.com/mybatis/redis-cache), build it into jar and install it manually into our pom.xml file from local folder.

Okay, so here is my pom.xml file, you can see im manually installing mybatis-redis from local repository,

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.edw</groupId>
    <artifactId>MybatisRedisExample</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <repositories>
        <repository>
            <id>local</id>
            <url>file://${basedir}/lib</url>
        </repository>
    </repositories>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.2</version>
        </dependency>
        
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-redis</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.3</version>
        </dependency>
        
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.6.2</version>
        </dependency>
    </dependencies>
</project>

Now create a database and a simple table for example,

CREATE DATABASE `test`;
DROP TABLE IF EXISTS `testing`;
CREATE TABLE `testing` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `address` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;


INSERT INTO `testing` VALUES ('1', 'edw', '123');
INSERT INTO `testing` VALUES ('2', 'pepe', 'epep');
INSERT INTO `testing` VALUES ('3', 'dodol', 'dodll');

And a java bean for our table representation

package com.edw.mybatisredisexample.bean;

public class Testing {

    private String name;
    private String address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Testing() {
    }
}

And an xml file and a java file, named TestingMapper to handle all the queries,

package com.edw.mybatisredisexample.mapper;

import com.edw.mybatisredisexample.bean.Testing;
import java.util.List;
import java.util.Map;

public interface TestingMapper {
    void insert(Testing testing);
    List<Map> select();
}
<?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.mybatisredisexample.mapper.TestingMapper" >
    
    <cache type="org.mybatis.caches.redis.RedisCache" />
    
    <select id="insert" parameterType="com.edw.mybatisredisexample.bean.Testing" >
        insert into testing (name, address)
        values ( #{name,jdbcType=VARCHAR}, #{address,jdbcType=VARCHAR} )
    </select>
    
    <select resultType="java.util.Map" id="select" >
        SELECT
            *
        FROM
            testing
    </select>
</mapper>

Dont forget to register our xml file on MyBatis’ Configuration.xml

<?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="password"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="TestingMapper.xml" />
    </mappers>
</configuration>

And a java class to load our MyBatis xml configuration

package com.edw.mybatisredisexample.config;

import java.io.IOException;
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 {

    private static final SqlSessionFactory FACTORY;

    static {
        try {
            Reader reader = Resources.getResourceAsReader("Configuration.xml");
            FACTORY = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            throw new RuntimeException("Fatal Error. Cause: " + e, e);
        }
    }

    public static SqlSessionFactory getSqlSessionFactory() {
        return FACTORY;
    }
}

Next is creating our Redis connection configuration, redis.properties

redis.host=localhost
redis.port=6379
redis.timeout=5000
redis.password=
redis.namespace=edw
redis.database=0

After everything is ready, next is create a Main file

package com.edw.mybatisredisexample;

import com.edw.mybatisredisexample.config.MyBatisSqlSessionFactory;
import com.edw.mybatisredisexample.mapper.TestingMapper;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

public class Main {

    private Logger logger = Logger.getLogger(this.getClass());

    public static void main(String[] args) throws Exception {
        new Main().testQuery();
    }

    private void testQuery() throws Exception {
        logger.debug("start ----");

        for (int i = 0; i < 10; i++) {
            SqlSession sqlSession = null;
            try {
                sqlSession = MyBatisSqlSessionFactory.getSqlSessionFactory().openSession(true);
                TestingMapper testingMapper = sqlSession.getMapper(TestingMapper.class);
                List<Map> maps = testingMapper.select();

                for (Map map : maps) {
                    logger.debug(map);
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            } finally {
                if (sqlSession != null) {
                    sqlSession.close();
                }
            }
            
            Thread.sleep(5000);
        }

        logger.debug("end ----");
    }
}

Using monitor command, this is what you will see on your Redis console,
redis console

And on my netbeans console,mybatis redis result log 2

It will keep showing the same value despite i’ve delete and update some values on database directly,
mysql data redis

You can see my complete sourcecode on my github page (https://github.com/edwinkun/MybatisRedisExample).

Google+

Create an Expirable Token Using Java

On this article, im trying to create a simple java app that will hold a value that have an expiration time. I usually use this for handling request session or to hold a value that have a time limitation. Btw, i’m using EhCache for handling expiration time.

First is a simple pom.xml,

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edw</groupId>
    <artifactId>ExpirableToken</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>ExpirableToken</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.7.4</version>
        </dependency>           
    </dependencies>
</project>

And a simple xml file to hold ehcache configurations,

<ehcache updateCheck="false" monitoring="off" dynamicConfig="false">
    
    <diskStore path="java.io.tmpdir" />
    
    <defaultCache maxEntriesLocalHeap="0" eternal="false"
                  timeToIdleSeconds="1200" timeToLiveSeconds="1200">
    </defaultCache>
    
    <!-- a 3 seconds -->
    <cache name="token" maxElementsInMemory="1000" eternal="false"
           overflowToDisk="true" diskPersistent="false" timeToIdleSeconds="3" 
           timeToLiveSeconds="3" memoryStoreEvictionPolicy="LFU" statistics="false" transactionalMode="off">       
    </cache>                
    
    <!-- a 10 seconds -->
    <cache name="action" maxElementsInMemory="1000" eternal="false"
           overflowToDisk="true" diskPersistent="false" timeToIdleSeconds="10" 
           timeToLiveSeconds="10" memoryStoreEvictionPolicy="LFU" statistics="false" transactionalMode="off">       
    </cache>        
    
</ehcache>

And this is my java class that i use for testing,

package com.edw.expirabletoken;

import java.util.Date;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

public class App {

    private CacheManager cacheManager= CacheManager.create();
    private Cache tokenCache = cacheManager.getCache("token"); // a 3 seconds cache
    private Cache actionCache = cacheManager.getCache("action"); // a 10 seconds cache

    public App() {
    }

    private void action() throws Exception {
        // add into a 3 seconds cache
        Element regElement = new Element("name", "edwin 3 seconds");
        tokenCache.put(regElement);
        
        // add into a 10 seconds cache
        Element regElement2 = new Element("name", "edwin 10 seconds");
        actionCache.put(regElement2);
        
         // 2 seconds sleep
         Thread.sleep(2000);
         getCacheContent();
         
         // 5 seconds sleep
         Thread.sleep(5000);
         getCacheContent();
         
         // 10 seconds sleep
         Thread.sleep(10000);
         getCacheContent();
    }
    
    private void getCacheContent() {
        Element element3 = tokenCache.get("name"); // get value from a 3 seconds cache
        if (element3 != null) {
            String value = (String) element3.getObjectValue();
            System.out.println(new Date()+" -- "+value);    
        } else {
            System.out.println(new Date()+" -- Empty Cache");
        }
        
         Element element10 = actionCache.get("name"); // get value from a 10 seconds cache
         if (element10 != null) {
            String value = (String) element10.getObjectValue();
            System.out.println(new Date()+" -- "+value);    
        } else {
            System.out.println(new Date()+" -- Empty Cache");
        }
    }
    
    public static void main(String[] args) throws Exception {
        App app = new App();
        app.action();
    }
}

This is what the result on my Netbeans’ console,

This is my Netbeans’ project structure,

Well i hope this helped others, have fun using ehcache.

Google+

A Simple Caching Example on MyBatis using EhCache

Today i will show a simple example on how to combine ehcache caching framework with MyBatis ORM. I use Maven as my build tool, and Netbeans as my IDE.

Okay, here is my pom.xml,

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.edw.ehcache</groupId>
    <artifactId>MyBatisEhCache</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>MyBatisEhCache</name>
    <url>http://maven.apache.org</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>      
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>     
    </dependencies>
</project>

And i create a simple mysql table,

CREATE TABLE `testing` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL DEFAULT '',
  `address` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`Id`),
  UNIQUE KEY `ix` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;

and a simple bean and xml representation from my table,

package com.edw.mybatisehcache.bean;

import java.io.Serializable;

public class Testing implements Serializable  {

    private Integer id;
    private String name;
    private String address;

    // setter and getter

    @Override
    public String toString() {
        return "testing{" + "id=" + id + ", name=" + name + ", address=" + address + '}';
    }            
}
<?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.mybatisehcache.mapper.TestingMapper" >
  
     <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    
    <resultMap id="Testings" type="com.edw.mybatisehcache.bean.Testing" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="address" property="address" jdbcType="VARCHAR" />
    </resultMap>  

    <select id="select" resultMap="Testings">
        select 
        *
        from testing    
    </select>   
</mapper>

An xml configuration to load my database connection,

<?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/mybatisehcache/xml/TestingMapper.xml" />  
    </mappers>              		
</configuration>

A java code to load my xml configuration,

package com.edw.mybatisehcache.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 {

    private static final SqlSessionFactory FACTORY;

    static {
        try {
            Reader reader = Resources.getResourceAsReader("com/edw/mybatisehcache/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;
    }
}

A java interface to do handle queries,

package com.edw.mybatisehcache.mapper;

import com.edw.mybatisehcache.bean.Testing;
import java.util.List;

public interface TestingMapper {
    public List<Testing> select();    
}

And this is my ehcache.xml configuration,

<?xml version="1.0" encoding="UTF-8"?>
<!--
    caching configuration
-->
<ehcache>
    
    <diskStore path="F:\\cache" />
    
    <defaultCache eternal="true" maxElementsInMemory="1000"
                   overflowToDisk="true" diskPersistent="true" timeToIdleSeconds="0"
                   timeToLiveSeconds="0" memoryStoreEvictionPolicy="LRU" statistics="true" />
</ehcache>

This is my main java class, as you can see i try to do a repeated simple select queries,

package com.edw.mybatisehcache.main;

import com.edw.mybatisehcache.bean.Testing;
import com.edw.mybatisehcache.config.MyBatisSqlSessionFactory;
import com.edw.mybatisehcache.mapper.TestingMapper;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.log4j.Logger;

public class Main {

    private static Logger logger = Logger.getLogger(Main.class);

    public static void main(String[] args) {

        for (int i = 0; i < 3; i++) {
            SqlSessionFactory sqlSessionFactory = MyBatisSqlSessionFactory.getSqlSessionFactory();
            SqlSession sqlSession = sqlSessionFactory.openSession();
            TestingMapper testingMapper = sqlSession.getMapper(TestingMapper.class);

            List<Testing> testings = testingMapper.select();
            for (Testing testing : testings) {
                logger.debug(testing);
            }
            sqlSession.close();

            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                logger.error(e, e);
            }
        }
    }
}

This is what is written on my netbeans’ console,

2013-07-25 15:30:10,648 [Segment] DEBUG net.sf.ehcache.store.disk.Segment:779 - fault removed 0 from heap
2013-07-25 15:30:10,648 [Segment] DEBUG net.sf.ehcache.store.disk.Segment:796 - fault added 0 on disk
2013-07-25 15:30:13,722 [Cache] DEBUG net.sf.ehcache.Cache:1970 - Cache: com.edw.mybatisehcache.mapper.TestingMapper store hit for 2026218237:1652924294:com.edw.mybatisehcache.mapper.TestingMapper.select:0:2147483647:select 
        *
        from testing
2013-07-25 15:30:13,722 [Main] DEBUG com.edw.mybatisehcache.main.Main:24 - testing{id=1, name=edw, address=Ciledug}
2013-07-25 15:30:13,722 [Main] DEBUG com.edw.mybatisehcache.main.Main:24 - testing{id=2, name=kamplenk, address=Cikokol}
2013-07-25 15:30:13,722 [Main] DEBUG com.edw.mybatisehcache.main.Main:24 - testing{id=3, name=nugie, address=Pamulang}
2013-07-25 15:30:13,722 [Main] DEBUG com.edw.mybatisehcache.main.Main:24 - testing{id=4, name=tebek, address=Karawaci}

Here is my Netbeans project structure

Have fun (K)

Google+