Ingeniero en Informática
Somos expertos en Java/J2EE
Fecha de publicación del tutorial: 2006-09-07
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:
iBatis DAO (opcional)
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>
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);
}
}
}
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);
}
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;
}
}
iBatis sqlMap
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>
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
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.
A continuación puedes evaluarlo:
Fecha publicación: 2012-02-13-18:29:23
Autor: Renzo
Fecha publicación: 2012-02-13-18:29:11
Autor: Renzo
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 <=41 and >=60
Gracias.
Fecha publicación: 2010-09-14-12:07:41
Autor: jcarmonaloeches
Fecha publicación: 2009-04-27-09:58:33
Autor:
Fecha publicación: 2007-03-15-11:24:08
Autor:
Fecha publicación: 2006-09-20-05:59:21
Autor:
Fecha publicación: 2006-09-13-05:03:24
Autor:
Fecha publicación: 2006-09-09-08:41:17
Autor:












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 <=41 and >=60
Gracias.