Manual Básico de Apache iBatis

3
60524

Manual Básico de
Apache iBatis

Introducción

¿Qué es iBatis?

Apache iBatis
está constituido por dos frameworks independientes que
generalmente se usan juntos: DAO y sqlMaps. El primero simplifica la
implementación el patrón de diseño Direct Access
Objects (DAO) y el segundo simplifica la persistencia de objetos en
bases de datos relacionales.

iBatis NO es un
ORM (Object Relational Mapper), por lo que se pueden utilizar modelos
de datos existentes o poco normalizados y, finalmente, no es
completamente transparente (el programador programa el SQL)

Ambos frameworks
de iBatis han sido portados a .NET con notable éxito y
popularidad. Ambas versiones ya son releases estables y maduras.

¿Para qué sirve?

El patrón
DAO nos ayuda a organizar las tareas de persistencia (guardado,
búsqueda, recuperación, borrado, etc.) de los objetos y
nos permite definir múltiples implementaciones para un mismo
objeto mediante la definición de una interfaz. Por ejemplo, la
interfaz UsuarioDao tiene los metodos guardarUsuario(Usuario
usuario), obtenerUsuario(String loginId), etc y dos implementaciones:
UsuarioMySqlDao y UsuarioLdapDao donde implementamos las operaciones
para MySql y Ldap respectivamente. Con iBatis DAO podremos configurar
cuándo usar una u otra implementación sin necesidad de
modificar código. Además, agregar un UsuarioOracleDao
será muy fácil y no implicará modificar código
del resto de la aplicación.

Cuando hacemos
un análisis y diseño orientado a objetos obtenemos
nuestro modelo de clases y también diseñamos el modelo
de datos donde se almacena la información. Y siempre nos queda
la tarea de conectarnos con una base de datos, crear statements,
construir selects/updates/etc, recorrer resultsets y setear atributos
de objetos, etc. para guardar, buscar, recuperar, etc. los valores de
los atributos de un objeto. iBatis sqlMap simplifica esta tarea
resumiéndola a la configuración de ficheros XML, con
SQL ANSI o propietario y funciona con prácticamente cualquier
base de datos con driver JDBC.

¿Cuándo utilizar iBatis?

Como toda herramienta,
no vale para todo. iBatis sqlMap es muy válido cuando:

  • Se requiere una
    curva de aprendizaje rápida y pocos conocimientos previos, y
    no requiere aprender un lenguaje de consultas como en Hibernate o
    EJB CMP.

  • Se necesita
    manipular el SQL (para utilizar SQL propietario, optimizarlo, etc.)
    o se necesita llamar a procedimientos almacenados.

  • El modelo de datos
    existe previamente y no está muy normalizado (aunque
    lógicamente se puede utilizar con modelos nuevos y
    normalizados)

  • Alto rendimiento y
    optimización

…pero no para
cuando:

  • Se requiere una
    automatización total y transparente de la persistencia

  • Se requiere
    soporte multi-RDBMS (motor de base de datos) transparente y
    automática

Hay una comparación
constructiva con Hibernate en
http://raibledesigns.com/page/rd?entry=hibernate_vs_ibatis

iBatis DAO es válido
cuando:

  • Se sabe que el
    RDBMS (motor de base de datos) puede cambiar en el futuro

  • La implementación
    del acceso a datos puede requerir cambios sustanciales en el futuro

  • La implementación
    del acceso a datos puede variar entre un entorno de producción
    y otro (software comercial en distintos clientes)

iBatis DAO soporta
sqlMap, Hibernate, etc.

¿Cómo funciona esto internamente?

Básicamente,
programación declarativa y extensión del framework. Es
decir, se configuran ficheros XML y, en iBatis DAO, se extienden
clases donde se implementa la interfaz y el comportamiento
específico.

Ejemplo:

  1. iBatis DAO
    (opcional)

    1. Crear un
      DAO.XML

<!DOCTYPE
daoConfig PUBLIC «-//iBATIS.com//DTD DAO Configuration 2.0//EN»
«http://www.ibatis.com/dtd/dao-2.dtd»>

<daoConfig>

<context>

<transactionManager
type=»SQLMAP»>

<property
name=»SqlMapConfigResource»

value=»es/dxd/km/dao/sqlMap/sqlMapConfig.xml»
/>

</transactionManager>

<dao
interface=»es.dxd.km.dao.UsuarioDao»

implementation=»es.dxd.km.dao.sqlMap.UsuarioSqlMapDao»
/>

</context>

</daoConfig>

    1. Crear una
      utilidad de configuración tipo DaoConfig

public
class DaoConfig {

private
static final String DAO_XML = «es/dxd/km/dao/dao.xml»;

private
static final DaoManager daoManager;

static
{

try
{

daoManager
= newDaoManager();

}
catch (Exception e) {

throw
new RuntimeException(«Description. Cause: » + e, e);

}

}

public
static DaoManager getDaoManager() {

return
daoManager;

}

public
static DaoManager newDaoManager() {

try
{

Reader
reader = Resources.getResourceAsReader(DAO_XML);

return
DaoManagerBuilder.buildDaoManager(reader, null);

}
catch (Exception e) {

throw
new RuntimeException(

«Could
not initialize DaoConfig. Cause: » + e, e);

}

}

}

    1. Crear la
      interfaz del Dao para Usuarios, UsuariosDao:

public
interface UsuarioDao extends Dao {

public
int updateUsuario(Usuario usuario);

public
int insertUsuario(Usuario usuario);

public
int deleteUsuario(String idUsuario);

public
Usuario getUsuario(String idUsuario);

public
Usuario getUsuarioValidado(String idUsuario, String password);

public
List getUsuariosByExample(Usuario usuario);

}

    1. Crear su
      implementación:

public
class UsuarioSqlMapDao extends SqlMapDaoTemplate implements

es.dxd.km.dao.UsuarioDao
{

public
UsuarioSqlMapDao(DaoManager arg0) {

super(arg0);

}

public
int updateUsuario(Usuario usuario) {

try
{

return
getSqlMapExecutor().update(«updateUsuario», usuario);

}
catch (SQLException e) {

throw
new DaoException(«Error actualizando usuario. Cause: » + e,
e);

}

}

public
int insertUsuario(Usuario usuario) {

try
{

getSqlMapExecutor().insert(«insertUsuario»,
usuario);

}
catch (SQLException e) {

throw
new DaoException(«Error insertando usuario. Cause: » + e,
e);

}

return
1;

}

public
int deleteUsuario(String idUsuario) {

try
{

return
getSqlMapExecutor().delete(«deleteUsuario», idUsuario);

}
catch (SQLException e) {

throw
new DaoException(«Error actualizando usuario. Cause: » + e,
e);

}

}

public
Usuario getUsuario(String idUsuario) {

try
{

Usuario
usuario = (Usuario) getSqlMapExecutor().queryForObject(

«getUsuarioById»,
idUsuario);

usuario.setRoles((List)
getSqlMapExecutor().queryForList(

«getRolesUsuario»,
usuario));

return
usuario;

}
catch (SQLException e) {

throw
new DaoException(«Error recuperando usuario. Cause: » + e,
e);

}

}

public
List getUsuariosByExample(Usuario usuario) {

try
{

Usuario
usuarioExample = new Usuario();

if
(usuario.getApellidos() != null) {

usuarioExample.setApellidos(«%»

+
usuario.getApellidos().toLowerCase() + «%»);

}

if
(usuario.getNombre() != null) {

usuarioExample.setNombre(«%»

+
usuario.getNombre().toLowerCase() + «%»);

}

usuarioExample.setIdUsuario(usuario.getIdUsuario());

List
usuarios = (List) getSqlMapExecutor().queryForList(

«getUsuariosByExample»,
usuarioExample);

//
Asignar los roles

for
(Iterator iter = usuarios.iterator(); iter.hasNext();) {

Usuario
usuario2 = (Usuario) iter.next();

usuario2.setRoles((List)
getSqlMapExecutor().queryForList(

«getRolesUsuario»,
usuario2));

}

return
usuarios;

}
catch (SQLException e) {

throw
new DaoException(«Error recuperando usuarios. Cause: » + e,
e);

}

}

public
Usuario getUsuarioValidado(String idUsuario, String password) {

Usuario
usuario = getUsuario(idUsuario);

return
usuario.getPassword().equals(password) ? usuario : null;

}

}

  1. iBatis sqlMap

    1. Crear la
      configuración sqlMapConfig.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>

<properties

resource=»properties/SqlMapConfig.properties»
/>

<settings
cacheModelsEnabled=»true» enhancementEnabled=»true»

lazyLoadingEnabled=»true»
maxRequests=»32″ maxSessions=»10″

maxTransactions=»5″
useStatementNamespaces=»false» />

<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=»es/dxd/km/dao/sqlMap/Usuario.xml»
/>

</sqlMapConfig>

    1. La
      configuración de contexto es preferible sacarla afuera del
      xml para, por ejemplo, cambiar fácilmente de entornos, en
      el sqlMapConfig.xml se indicó que estuviera en
      properties/SqlMapConfig.properties:

driver=org.apache.derby.jdbc.ClientDriver

url=jdbc:derby://localhost:1527/kmdb

username=derby

password=derby

    1. Finalmente, se
      configuran las operaciones y su SQL en Usuario.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=»Usuario»>

<select
id=»getUsuarioById» resultClass=»es.dxd.km.model.Usuario»>

SELECT
rtrim(ID_USUARIO) as idUsuario, rtrim(PASSWORD) as

password,
rtrim(NOMBRE) as nombre, rtrim(APELLIDOS) as apellidos

FROM
APP.USUARIOS WHERE id_usuario = #value#

</select>

<select
id=»getRolesUsuario»

parameterClass=»es.dxd.km.model.Usuario»

resultClass=»es.dxd.km.model.Rol»>

SELECT
rtrim(R.ID_ROL) as idRol, rtrim(R.NOMBRE) as nombre,

rtrim(R.DESCRIPCION)
as descripcion FROM APP.ROLES R,

APP.USUARIOS_ROLES
U WHERE R.ID_ROL = U.ID_ROL AND U.ID_USUARIO

=
#idUsuario#

</select>

<select
id=»getUsuariosByExample»

parameterClass=»es.dxd.km.model.Usuario»

resultClass=»es.dxd.km.model.Usuario»>

SELECT
rtrim(ID_USUARIO) as idUsuario, rtrim(PASSWORD) as

password,
rtrim(NOMBRE) as nombre, rtrim(APELLIDOS) as apellidos

FROM
APP.USUARIOS

<dynamic
prepend=»WHERE»>

<isNotNull
prepend=»AND» property=»nombre»>

lower(NOMBRE)
like #nombre#

</isNotNull>

<isNotNull
prepend=»AND» property=»apellidos»>

lower(APELLIDOS)
like #apellidos#

</isNotNull>

<isNotNull
prepend=»AND» property=»idUsuario»>

ID_USUARIO
= #idUsuario#

</isNotNull>

</dynamic>

</select>

<insert
id=»insertUsuario»

parameterClass=»es.dxd.km.model.Usuario»>

INSERT
INTO APP.USUARIOS (ID_USUARIO, PASSWORD, NOMBRE,

APELLIDOS)
VALUES (#idUsuario#, #password#, #nombre#,

#apellidos#)

</insert>

<update
id=»updateUsuario»

parameterClass=»es.dxd.km.model.Usuario»>

UPDATE
APP.USUARIOS SET PASSWORD = #password#, NOMBRE =

#nombre#,APELLIDOS
= #apellidos# WHERE ID_USUARIO = #idUsuario#

</update>

<delete
id=»deleteUsuario» parameterClass=»string»>

DELETE
FROM APP.USUARIOS WHERE ID_USUARIO = #value#

</delete>

</sqlMap>

¿Licencia?

iBatis
es un proyecto que pertenece y utilza la licencia de Apache Software
Foundation, por lo que es Open Source disponible, modificable y
comercializable libremente.
(todo asesoramiento en este tema será
bienvenido)

¿Y para qué este manual básico?

Para simplificar el
«first touch» y para explicar iBatis a alto nivel.

No pretende ser un
tutorial, una guía del usuario ni un manual de referencia.
Ellos ya se han escrito y están disponibles en las direcciones
que se mencionan en la sección «¿Dónde
encuentro más info?»

¿Dónde encuentro más info?

En la Página
Oficial http://ibatis.apache.org
encontrarán en la sección Documentación unos
tutoriales muy buenos aunque extensos, una guía de referencia
y el JavaDoc de la API. También tienen una sección de
preguntas frecuentes muy completa.

Desde esta página
también se puede descargar (recomiendo) el ejemplo oficial de
utilización de iBatis: el JPetStore. Viene a ser como el
PetStore de J2EE reconvertido a Struts+iBatis.

¿Cómo pongo en funcionamiento
iBatis?

Básicamente hay
que incluir las librerías en el path (en las aplicaciones web,
en /WEB-INF/lib)

Lo ideal es deplegar el
war del JPetStore, descargable desde http://ibatis.apache.org,
y ver cómo funciona. Hacerle alguna modificación.
Comenzar un prototipo desde cero y seguir los tutoriales.

Consejo: ser muy
meticuloso con los XML porque la info de debugging es escasa y
confusa.

3 COMENTARIOS

  1. Hola, para el caso de Ibatis como puedo obtener un rango de registros, por ejemplo de 100 registros quiero obtenter del 41 al registro 60. algo como =60

    Gracias.

  2. Este tutorial me va a servir para conocer IBATIS, pues aca en Chile lo piden mucho en los perfiles analista programador Java.

    Gracias Javier !!!

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad