Java

java programming

[Weird Issue] Slow Database Query Which only Happen in Windows Server 2008 64Bit

Several days ago, i was asked by my friend to fix one of his weird issue. A same java webapp deployed on two different Operating System, Windows Server 2003 32bit and Windows Server 2008 64bit, gives two different performance. The webapp runs well on Windows Server 2003, while at the same time have a very poor performance on Windows Server 2008. Same identical infrastructure, the only differences is the Windows Server version.

Later i will show you how to fix this issue, but first let me show what the infrastructure looks like. Basically, it’s a three tier infrastructure, a load balancer, multiple webserver and database server. At first, i thought that the bottleneck is on network infrastructure, but the network guy says that there is nothing wrong on network’s monitoring.

After several days monitoring, i found out that the main culprit is Windows Server 2008. Somehow there are some issues on network outbound causing a very slow database queries.

So this is to fix it, first via netsh interface

netsh interface tcp set global rss=disabled
netsh interface tcp set global autotuning=disabled
netsh interface tcp set global chimney=disabled

netsh1

netsh2

Next is disabling QoS Packet Scheduler,
qos

And last is adding a TcpNoDelay variable in windows server’s regedit, which located at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters
tcpnodelay

After i run those command and restart my machine, my application on Windows Server 2008 run smoothly.

[Java] Creating a Microsoft Word Report Easily using Servlet and A Plain HTML Template

Yesterday one of my friend, Edward Barchia, asked me a very simple question, “how can i creating an MSWord Report without using Jasper Report”. Because somehow, jasper report creates a very weird output when exported into Word file (.doc).

One fastest solution is using a html file, and renamed into .doc. Not an elegant solution, but perhaps (at that moment) is the best solution we had.

Okay, so basically what i need is only 2 files, 1 html template and a java servlet files. This is my HTML template, i put it on drie E and name it hello.html

<html>
	<head></head>
	<body>
		Test, hello ${name}
	</body>
</html>

And this is my servlet file,

package com.edw.testdownloaddoc.servlet;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;

@WebServlet(name = "downloadServlet", urlPatterns = {"/downloadServlet"})
public class DownloadServlet extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        BufferedReader downloadFile = new BufferedReader(new FileReader("e:\\hello.html"));
        FileInputStream inputStream = null;
        OutputStream outStream = null;
        try {
            String s;
            StringBuilder sb = new StringBuilder();
            while ((s=downloadFile.readLine()) != null) {
                if(s.contains("${name}"))
                    s = s.replace("${name}", "Edwin");
                sb.append(s);
            }
 
            response.setContentLength((int) sb.toString().length());
            response.setContentType("application/msword");           
 
            // response header
            String nameFile = "hello.doc";
            String headerKey = "Content-Disposition";
            String headerValue = String.format("attachment; filename=\"%s\"",nameFile);
            response.setHeader(headerKey, headerValue);
 
            // Write response
            outStream = response.getOutputStream();
            IOUtils.write(sb.toString(), outStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            IOUtils.closeQuietly(downloadFile);
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(outStream);
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
}

Oh, and before i forgot, this is my pom.xml dependencies

<dependencies>
	<dependency>
		<groupId>commons-io</groupId>
		<artifactId>commons-io</artifactId>
		<version>2.2</version>
	</dependency>
	<dependency>
		<groupId>javax</groupId>
		<artifactId>javaee-web-api</artifactId>
		<version>7.0</version>
		<scope>provided</scope>
	</dependency>
</dependencies>

This is the final output looks like,
helloworld

How to Perform “Autopsy” on OutOfMemoryError Application

Just several days ago, my application was down because of OutOfMemoryError, and I haven’t got a clue what the root cause is. That’s why I’m looking for a way on how to find the culprit when my application is down again. So im using this jvm parameter to dump all the object on memory when OutOfMemoryError happen.

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=E:\ -Xmx10m -Xms10m

For example, im using this java class to simulate OutOfMemoryError,

package mybatistesting;

import java.util.ArrayList;
import java.util.List;

public class MyBatisTesting {
    
    public static void main(String[] args) throws Exception {
        List list = new ArrayList();
        for (int i = 0; i < 10000000000l; i++) {
            list.add(i+""+i+""+i);
            if(i%1000==0)
                System.out.println("adding -- "+i);
        }
    }
}

As you can see on your console log,

java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to E:\java_pid5812.hprof ...
Heap dump file created [15155736 bytes in 0.237 secs]

You can open java_pid5812.hprof using your preferable application, for example using Eclipse MAT or JProfiler.

eclipse mat

jprofiler 1

jprofiler 2

Have fun 😉

Weird MyBatis Error, “Error setting null for parameter [number] with JdbcType OTHER”

I had a very weird error today, when connecting MyBatis to Oracle Database, the complete error is like this,

Error setting null for parameter #2 with JdbcType OTHER . 
Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. 
Cause: java.sql.SQLException: Invalid column type: 1111

After researching for a while, i found out that it happen because i miss to fill a parameter on mybatis xml query file. This is my xml file,

<?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="mybatistesting.MyMapper" >    
    <select resultType="java.util.Map" id="select" parameterType="java.util.Map">
        SELECT
            *
        FROM
            RISALAH
        WHERE UUID = #{UUID} AND CONTENT = #{CONTENT}
    </select>
</mapper>

And this is my main java file,

package mybatistesting;

import java.util.HashMap;
import java.util.Map;
import mybatistesting.config.MyBatisSqlSessionFactory;
import org.apache.ibatis.session.SqlSession;

public class MyBatisTesting {

    public static void main(String[] args) throws Exception {
        SqlSession sqlSession = MyBatisSqlSessionFactory.getSqlSessionFactory().openSession(true);
        MyMapper mapper = sqlSession.getMapper(MyMapper.class);
        Map map1 = new HashMap();
        map1.put("UUID", "1");
        for (Map map : mapper.select(map1)) {
            System.out.println("map "+map);
        }
    }
}

As you can see, i only set UUID as query parameter on my java file, despite that i need at least 2 parameter on my xml file. Here is how to fix it,

package mybatistesting;

import java.util.HashMap;
import java.util.Map;
import mybatistesting.config.MyBatisSqlSessionFactory;
import org.apache.ibatis.session.SqlSession;

public class MyBatisTesting {

    public static void main(String[] args) throws Exception {
        SqlSession sqlSession = MyBatisSqlSessionFactory.getSqlSessionFactory().openSession(true);
        MyMapper mapper = sqlSession.getMapper(MyMapper.class);
        Map map1 = new HashMap();
        map1.put("UUID", "1");
        map1.put("CONTENT", "1");
        for (Map map : mapper.select(map1)) {
            System.out.println("map "+map);
        }
    }
}

Hope it helps others, cheers 😉

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).