Geralmente quando se fala sobre frameworks de persistência logo vem à cabeça Hibernate/JPA. Há pouco tempo fui apresentado ao iBatis, um framework que eu, particularmente, acho muito fácil de instalar, configurar e usar. Você pode baixa-lo através do site de sua mantenedora, a Apache, clicando aqui.

Neste tutorial usarei a versão 2.3.4 build 726.

Configurando o iBatis

Ao contrário dos demais frameworks, para configurar o iBatis você só precisa de um arquivo XML de configuração, chamado SqlMapConfig.

As principais seções do xml são:

<properties resource="tuto/ibatis/config/SqlMap.properties"/>

Este código é opcional e serve para indicar o arquivo properties com as variável de configuração que serão usada no XML.

<typeAlias alias="car" type="tuto.ibatis.beans.Car"/>

Indica o Bean utilizado e qual será seu aliás. Você pode configurar várias linhas, tudo depende da complexidade e necessidade da sua modelagem.
No nosso exemplo, usaremos o bean Car abaixo:

public class Car {
	private Long carId;
	private String company;
	private String model;
	private String color;
	private Integer	hp;
	private Float price;

	//Setters e getters omitidos
}
<transactionManager type="JDBC">
    <dataSource type="SIMPLE">
        <property name="JDBC.Driver" value="${driver}"/>
        <property name="JDBC.ConnectionURL" value="${url}"/>
        <property name="JDBC.Username" value="${username}"/>
        <property name="JDBC.Password" value="${password}"/>
    </dataSource>
</transactionManager>

Parâmetros usados na conexão com o banco. As variáveis ${driver}, ${url}, ${username} e ${password} estão definidas no arquivo .properties indicado na seção  properties. Se você preferir, também pode colocar os valores diretamente nos campos, sem precisar defini-los em outro local.

Veja como será arquivo completo:

<?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>
    <properties resource="tuto/ibatis/config/SqlMap.properties"/>

    <settings
        cacheModelsEnabled="true"
        enhancementEnabled="true"
        lazyLoadingEnabled="true"
        maxRequests="32"
        maxSessions="10"
        maxTransactions="5"
        useStatementNamespaces="false" />

    <typeAlias alias="car" type="tuto.ibatis.beans.Car"/>

    <transactionManager type="JDBC">
        <dataSource type="SIMPLE">
            <property name="JDBC.Driver" value="${driver}"/>
            <property name="JDBC.ConnectionURL" value="${url}"/>
            <property name="JDBC.Username" value="${username}"/>
            <property name="JDBC.Password" value="${password}"/>
        </dataSource>
    </transactionManager>

    <sqlMap resource="tuto/ibatis/sqlmaps/CarSqlMap.xml"/>
</sqlMapConfig>

O properties tem o seguinte conteúdo:

driver=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@<host>:<porta>:<sid>
username=<login>
password=<senha>

Em seguida devemos configurar nosso SqlMap. Este XML conterá as querys utilizadas na aplicação e deverá ter o nome do descrito na seçao sqlMap do SqlMapConfig, no nosso caso será CarSqlMap.xml.

No nosso exemplo apenas veremos a utilização das tags select, insert, update e delete.

<select id="getCars" resultClass="tuto.ibatis.beans.Car"
	parameterClass="java.lang.Long">
    SELECT COMPANY  as company,
           MODEL    as model,
           COLOR    as color,
           HP       as hp,
           PRICE    as price
    FROM TBL_CAR
    WHERE CAR_ID = #var#
</select>

Executa o select podendo retornar uma única linha ou uma coleção, o tipo retornado é o mesmo especificado no atributo resultClass, o parameterClass é o tipo passado para executar a query e o id é a identificação para chamada da query.

Usaremos o SqlMap abaixo:

<?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="Car">
    <select id="getCars" resultClass="tuto.ibatis.beans.Car"
    parameterClass="java.lang.Long">
        SELECT COMPANY  as company,
               MODEL    as model,
               COLOR    as color,
               HP       as hp,
               PRICE    as price
        FROM TBL_CAR
        WHERE CAR_ID = #var#
    </select>

    <insert id="addCar" parameterClass="tuto.ibatis.beans.Car">
        INSERT INTO TBL_CAR (CAR_ID, COMPANY, MODEL, COLOR, HP, PRICE)
        VALUES (#carId#, #company#, #model#, #color#, #hp#, #price#)
    </insert>

    <delete id="delCar" parameterClass="java.lang.Long">
        DELETE FROM TBL_CAR WHERE CAR_ID = #var#
    </delete>

    <update id="updCar" parameterClass="tuto.ibatis.beans.Car">
        UPDATE TBL_CAR
          SET COMPANY = #company#,
              MODEL = #model#,
              COLOR = #color#,
              HP = #hp#,
              PRICE = #price#
        WHERE CAR_ID = #carId#
    </update>
</sqlMap>

Agora que já configuramos o acesso ao banco de dados e o mapeamento dos objetos, vamos implementar a classe singleton que usaremos como SqlMapClient, aqui nós a chamaremos de OracleMapConfig.

package tuto.ibatis.connection;

import java.io.Reader;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

public class OracleMapConfig {
	private static final SqlMapClient sqlMapClient;

	static{
		try{
			//Definindo o caminho para o SqlMapConfig e criando o reader
			String res = "tuto/ibatis/config/SqlMapConfig.xml";
			Reader reader = Resources.getResourceAsReader(res);

			//Recuperando o client para o SqlMap
			sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
		} catch(Exception e){
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	//Método usado para recuperar o client
	public static SqlMapClient getSqlMapClient(){
		return sqlMapClient;
	}
}

O client é responsável por executar as querys configuradas no SqlMap e nos fornecer os resultados.

Executando Querys e tratando retornos

Para chamar uma das querys é muito simples, apenas chame o cliente e o método correspondente de cada uma.

O select pode ser chamado da seguinte forma:

OracleMapConfig.getSqlMapClient().queryForObject("<id>", <parâmetro>);

O iddeve ser o id correspondente no SqlMap

O código acima tráz apenas uma linha retornada pela query, para trazer todas apenas troque o método para o queryForList, desta forma:

OracleMapConfig.getSqlMapClient().queryForList("<id>", <parâmetro>);

Assim, será retornado uma Collection contendo os objetos.

Vamos aos exemplos:
Select

try{
	Car car = (Car)OracleMapConfig.getSqlMapClient().queryForObject("getCars",
		new Long(readKeyboard()));

	System.out.println("Marca: "+car.getCompany());
	System.out.println("Modelo: "+car.getModel());
	System.out.println("Cor: "+car.getColor());
	System.out.println("HP: "+car.getHp());
	System.out.println("Preço: "+car.getPrice());
}catch (Exception e) {
	e.printStackTrace();
}

O id “getCars” é o que definimos nos atributos do select do SqlMap, passando um Long e recuperando o tipo Car, ambos também definidos na linha <select id=”getCars” resultClass=”tuto.ibatis.beans.Car” parameterClass=”java.lang.Long“>.

Insert

try{
	OracleMapConfig.getSqlMapClient().insert("addCar", newCar);
}catch (Exception e) {
	e.printStackTrace();
}

Agora passamos como parâmetros o próprio tipo Car, <insert id=”addCar” parameterClass=”tuto.ibatis.beans.Car“> e chamamos os métodos usando cerquilha (#, ou jogo-da-velha se preferirem), desta forma:

INSERT INTO TBL_CAR (CAR_ID, COMPANY, MODEL, COLOR, HP, PRICE)
VALUES (#carId#, #company#, #model#, #color#, #hp#, #price#)

Delete

try{
	int lines = OracleMapConfig.getSqlMapClient().delete("delCar",
		new Long(readKeyboard()));

	System.out.println(lines + " linhas excluídas");
}catch (Exception e) {
	e.printStackTrace();
}

O método delete do client retorna um tipo int que representa a quantidade de linhas excluídas.

Update

try{
	int lines = OracleMapConfig.getSqlMapClient().update("updCar", car);

	System.out.println(lines + " carros incluídos");
}catch (Exception e) {
	e.printStackTrace();
}

O Update retorna um tipo int, que informa a quantidade de linhas afetadas pelo update.

Como você pode ver, com apenas três arquivos XML e três classes conseguimos montar um sistema de manutenção de estoque de consulta de preço basico.

Você pode fazer o download com os fontes deste tutorial clicando aqui.

Até a próxima!