Saturday, February 8, 2014

How to enable lazy loading in iBatis

Lazy loading is conceptually a tactic of delaying the creation of an object until required. It is also referred as design pattern also. When we talk about lazy loading while fetching information from database, lazy loading essentially means to delay the execution of certain select/ sub-select queries till the time their related data is asked for.
In this tutorial, I am showing an example of lazy loading when developing your application with iBatis. There are following sections in this tutorial.
1) Create a maven project
2) Update runtime dependencies
3) Configure sql-map and config files with lazy loading enabled
4) Write domain classes
5) Test the application

1) Create a maven project

Run following commands to make a simple java project which is supported by eclipse plugin.
?
1
2
mvn archetype:generate -DgroupId=com.howtodoinjava.ibatis.demo -DartifactId=ibatisHelloWorld
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

2) Update runtime dependencies

This will be done in pom.xml file. You can download the required jar files and put in lib folder as well.
pom.xml
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<dependencies>
    
    <dependency>
        <groupId>org.apache.ibatis</groupId>
        <artifactId>ibatis-sqlmap</artifactId>
        <version>2.3.4.726</version>
    </dependency>
    
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.9</version>
    </dependency>
    
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
    </dependency>
    
    <dependency>
        <groupId>asm</groupId>
        <artifactId>asm-util</artifactId>
        <version>3.3.1</version>
    </dependency>
    
    <dependency>
        <groupId>opensymphony</groupId>
        <artifactId>oscache</artifactId>
        <version>2.4</version>
        <scope>compile</scope>
        
        <exclusions>
                <exclusion>
                        <groupId>javax.jms</groupId>
                        <artifactId>jms</artifactId>
                </exclusion>
        </exclusions>
    </dependency>

3) Write domain classes

Below the domain classes UserTEO.java and DepartmentTEO.java. UserTEO has reference of DepartmentTEO which we are targeting to lazy load.
UserTEO.java
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.howtodoinjava.ibatis.demo.dto;
 
import java.io.Serializable;
 
public class UserTEO implements Serializable
{
    private static final long serialVersionUID = 1L;
     
    private Integer id;
    private String name;
    private String email;
    private String password;
    private int status;
    private DepartmentTEO department;
     
    //Getters and Setters
}
DepartmentTEO.java
?
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.howtodoinjava.ibatis.demo.dto;
 
import java.io.Serializable;
 
public class DepartmentTEO implements Serializable
{
    private static final long serialVersionUID = 1L;
     
    private int id;
    private String name;
     
    //Getters and Setters
}

4) Configure sql-map and config files with lazy loading enabled

To configure iBatis in your application, you will need to configure sql-map-config.xml file and well as sql-map file also.
Below are two such files written for this tutorial.
sql-maps-config.xml
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
xml version="1.0" encoding="UTF-8" ?>
        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" cacheModelsEnabled="false" lazyLoadingEnabled="true"/>
     
    <transactionManager type="JDBC">
        <dataSource type="SIMPLE">
          <property name="JDBC.Driver" value="com.mysql.jdbc.Driver"/>
          <property name="JDBC.ConnectionURL"  value="jdbc:mysql://localhost:3306/demoDB"/>
          <property name="JDBC.Username" value="root"/>
          <property name="JDBC.Password" value="lg225295"/>
        </dataSource>
      </transactionManager>
     
    <sqlMap resource="user.xml"/>
 
</sqlMapConfig>
user.xml
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
xml version="1.0" encoding="UTF-8"?>
<sqlMap namespace="user">
 
    <typeAlias alias="USER" type="com.howtodoinjava.ibatis.demo.dto.UserTEO" />
    <typeAlias alias="DEPARTMENT" type="com.howtodoinjava.ibatis.demo.dto.DepartmentTEO" />
     
    <resultMap id="userResultMap" class="USER">
        <result property="id" column="ID" />
        <result property="name" column="NAME" />
        <result property="email" column="EMAIL" />
        <result property="password" column="PASSWORD" />
        <result property="status" column="STATUS" />
        <result property="department" column="DEPT_ID" select="user.getDepartmentById" />
    </resultMap>
     
    <resultMap id="departmentResultMap" class="DEPARTMENT">
        <result property="id" column="ID" />
        <result property="name" column="NAME" />
    </resultMap>
     
    <select id="getDepartmentById" parameterClass="java.lang.Integer" resultMap="departmentResultMap">
          SELECT * FROM DEPARTMENT WHERE ID = #value#
    </select>
     
    <select id="getUserById" parameterClass="java.lang.Integer" resultMap="userResultMap">
          SELECT * FROM USERINFO WHERE ID = #value#
    </select>
     
</sqlMap>

5) Test the application

I have written below code which loads the iBatis configuration, connects to DB and load user object. It first makes a call to user detail, the user object is loaded from database.
But Department data is selected only when I try to get it from user object. It means Department data is lazy loaded .
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.howtodoinjava.ibatis.demo;
 
import java.io.Reader;
 
import com.howtodoinjava.ibatis.demo.dao.UserDao;
import com.howtodoinjava.ibatis.demo.dao.UserDaoIbatis;
import com.howtodoinjava.ibatis.demo.dto.UserTEO;
import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
 
public class TestMain {
    public static void main(String[] args) throws Exception
    {
        UserDao manager = new UserDaoIbatis();
         
        Reader reader = Resources.getResourceAsReader("sql-maps-config.xml");
        SqlMapClient sqlmapClient = SqlMapClientBuilder.buildSqlMapClient (reader);
         
        UserTEO user = manager.getUserById(1, sqlmapClient);
        System.out.println(user.getEmail());
         
        System.out.println("LAZY load the department");
         
        System.out.println(user.getDepartment().getName());
    }
}
Below is the output of program.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DEBUG [main] - Created connection 27994366.
DEBUG [main] - {conn-100000} Connection
DEBUG [main] - {conn-100000} Preparing Statement:      SELECT * FROM USERINFO WHERE ID = ? 
DEBUG [main] - {pstm-100001} Executing Statement:      SELECT * FROM USERINFO WHERE ID = ? 
DEBUG [main] - {pstm-100001} Parameters: [1]
DEBUG [main] - {pstm-100001} Types: [java.lang.Integer]
DEBUG [main] - {rset-100002} ResultSet
DEBUG [main] - {rset-100002} Header: [ID, NAME, EMAIL, PASSWORD, STATUS, DEPT_ID]
DEBUG [main] - {rset-100002} Result: [1, Demo User, demo-user@howtodoinjava.com, password, 1, 1]
DEBUG [main] - Returned connection 27994366 to pool.
demo-user@howtodoinjava.com
LAZY load the department
DEBUG [main] - Checked out connection 27994366 from pool.
DEBUG [main] - {conn-100003} Connection
DEBUG [main] - {conn-100003} Preparing Statement:      SELECT * FROM DEPARTMENT WHERE ID = ? 
DEBUG [main] - {pstm-100004} Executing Statement:      SELECT * FROM DEPARTMENT WHERE ID = ? 
DEBUG [main] - {pstm-100004} Parameters: [1]
DEBUG [main] - {pstm-100004} Types: [java.lang.Integer]
DEBUG [main] - {rset-100005} ResultSet
DEBUG [main] - {rset-100005} Header: [ID, NAME]
DEBUG [main] - {rset-100005} Result: [1, Finance]
DEBUG [main] - Returned connection 27994366 to pool.
Finance
source download
Happy Learning !!

No comments: