Spring and iBATIS 2

Lately I was refactoring a application that acceses DB. Due it was using plain JDBC I decided to reimplement it using iBatis instead of Hibernate as I would do if starting from scratch.

I have used iBatis 1.x before, and now I decided to use the latest 2.0, and the Spring support.
I was keen to see that it was like using Hibernate support, very easy. In fact is easier to understand how things work than using Hibernate.

While reading the Spring reference guide I saw that the iBatis section didn’t cover most changes in
version 2, so I decided to complete it. You can read the full section here until Spring people update
it.

iBATIS

Through the org.springframework.orm.ibatis
package, Spring supports iBATIS SqlMaps 1.3.x and 2.0.x. The iBATIS
support much resembles Hibernate support in that it supports the same
template style programming and just as with Hibernate, iBatis support
works with Spring’s exception hierarchy and let’s you enjoy the all IoC
features Spring has.

4.1. Overview and differences between 1.3.x and 2.0

Spring supports both iBATIS SqlMaps 1.3 and 2.0. First let’s have a look at the differences between the two.

The
xml config files have changed a bit, node and attribute names. Also the
Spring clases you need to extend are different, as some method names.

Table 1.1. iBATIS SqlMaps supporting classes for 1.3 and 2.0

Feature 1.3.x 2.0
Creation of SqlMap SqlMapFactoryBean SqlMapClientFactoryBean
Template-style helper class SqlMapTemplate SqlMapClientTemplate
Callback to use MappedStatement SqlMapCallback SqlMapClientCallback
Super class for DAOs SqlMapDaoSupport SqlMapClientDaoSupport

4.2. iBATIS 1.3.x

4.2.1. Setting up the SqlMap

Using
iBATIS SqlMaps involves creating SqlMap configuration files containing
statements and result maps. Spring takes care of loading those using
the SqlMapFactoryBean.


public class Account {
	private String name;
	private String email;

	public String getName() {
		return this.name;
	}

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

	public String getEmail() {
		return this.email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
}

Suppose
we would want to map this class. We’d have to create the following
SqlMap. Using the query, we can later on retrieve users through their
email addresses. Account.xml:

<sql-map name="Account">
	<result-map name="result" class="examples.Account">
		<property name="name" column="NAME" columnIndex="1"/>
		<property name="email" column="EMAIL" columnIndex="2"/>
	</result-map>


	<mapped-statement name="getAccountByEmail" result-map="result">
		select
			  ACCOUNT.NAME,
			  ACCOUNT.EMAIL
		from ACCOUNT
		where ACCOUNT.EMAIL = #value#
	</mapped-statement>

	<mapped-statement name="insertAccount">
		insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
	</mapped-statement>
</sql-map>

After having defined the Sql Map, we have to create a configuration file for iBATIS (sqlmap-config.xml):

<sql-map-config>

	<sql-map resource="example/Account.xml"/>

</sql-map-config>

iBATIS loads resources from the classpath so be sure to add the Account.xml file to the classpath somewhere.

Using Spring, we can now very easily set up the SqlMap, using the SqlMapFactoryBean:

<bean id="sqlMap" class="org.springframework.orm.ibatis.SqlMapFactoryBean">
	<property name="configLocation"><value>WEB-INF/sqlmap-config.xml</value></property>

</bean>

4.2.2. Using SqlMapDaoSupport

The SqlMapDaoSupport class offers a supporting class similar to the HibernateDaoSupport and the JdbcDaoSupport types. Let’s implement a DAO:

public class SqlMapAccountDao extends SqlMapDaoSupport implements AccountDao {

	public Account getAccount(String email) throws DataAccessException {
		return (Account) getSqlMapTemplate().executeQueryForObject("getAccountByEmail", email);
	}

	public void insertAccount(Account account) throws DataAccessException {
		getSqlMapTemplate().executeUpdate("insertAccount", account);
	}
}

As you can see, we’re using the SqlMapTemplate to execute the
query. Spring has initialized the SqlMap for us using the
SqlMapFactoryBean and when setting up the SqlMapAccountDao as follows,
you’re all set to go:

<!-- for more information about using datasource, have a look at the JDBC chapter -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName"><value>${jdbc.driverClassName}</value></property>
	<property name="url"><value>${jdbc.url}</value></property>
	<property name="username"><value>${jdbc.username}</value></property>

	<property name="password"><value>${jdbc.password}</value></property>
</bean>

<bean id="accountDao" class="example.SqlMapAccountDao">
	<property name="dataSource"><ref local="dataSource"/></property>

	<property name="sqlMap"><ref local="sqlMap"/></property>
</bean>

4.2.3. Transaction management

It’s
pretty easy to add declarative transaction management to applications
using iBATIS. Basically the only thing you need to do is adding a
transaction manager to you application context and declaratively set
your transaction boundaries using for example the TransactionProxyFactoryBean. More on this can be found in ???

TODO elaborate!

4.3. iBATIS 2

4.3.1. Setting up the SqlMap

If we want to map the previous Account class with iBATIS 2 we need to create the following SqlMap Account.xml:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMap PUBLIC
  "-//iBATIS.com//DTD SQL Map 2.0//EN"
  "http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap namespace="Account">

	<resultMap id="result" class="examples.Account">
		<result property="name" column="NAME" columnIndex="1"/>
		<result property="email" column="EMAIL" columnIndex="2"/>
	</resultMap>

	<select id="getAccountByEmail" resultMap="result">
		select
			  ACCOUNT.NAME,
			  ACCOUNT.EMAIL
		from ACCOUNT
		where ACCOUNT.EMAIL = #value#
	</select>

	<insert id="insertAccount">
		insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
	</insert>

</sqlMap>

The configuration file for iBATIS 2 changes a bit (sqlmap-config.xml):

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig PUBLIC
  "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
  "http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

	<sqlMap resource="example/Account.xml"/>

</sqlMapConfig>

Remember that iBATIS loads resources from the classpath so be sure to add the Account.xml file to the classpath somewhere.

We can use the SqlMapClientFactoryBean in the Spring application context :

<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
	<property name="configLocation"><value>WEB-INF/sqlmap-config.xml</value></property>
</bean>

4.3.2. Using SqlMapClientDaoSupport

The SqlMapClientDaoSupport class offers a supporting class similar to the SqlMapDaoSupport. We extend it to implement our DAO:

public class SqlMapAccountDao extends SqlMapClientDaoSupport implements AccountDao {

	public Account getAccount(String email) throws DataAccessException {
		Account acc = new Account();
		acc.setEmail();
		return (Account)getSqlMapClientTemplate().queryForObject("getAccountByEmail", email);
	}

	public void insertAccount(Account account) throws DataAccessException {
		getSqlMapClientTemplate().update("insertAccount", account);
	}
}

In the DAO we use the SqlMapClientTemplate to execute the
queries, after setting up the SqlMapAccountDao in the application
context:

<!-- for more information about using datasource, have a look at the JDBC chapter -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName"><value>${jdbc.driverClassName}</value></property>

	<property name="url"><value>${jdbc.url}</value></property>
	<property name="username"><value>${jdbc.username}</value></property>
	<property name="password"><value>${jdbc.password}</value></property>

</bean>

<bean id="accountDao" class="example.SqlMapAccountDao">
	<property name="dataSource"><ref local="dataSource"/></property>
	<property name="sqlMapClient"><ref local="sqlMapClient"/></property>
</bean>

4 thoughts on “Spring and iBATIS 2

  1. Hello Carlos:
    I need to have more than one sqlMap in the sqlMap-config.xml. I did something like

    This would not work and throws an exception that sqlMaps need to be declared in my application context xml file. Any ideas as to what I could do to fix that?
    Thanks for any help.

  2. I have Eclipse 6 installed, I would like someone if it’s possible to help how to start with abatis.

    I have the jars I have included in my project but what else I have to do?

    Thanks a lot

Leave a comment