Mybatis con Maven y Spring

5
29714

0. Índice de contenidos.

1. Entorno

Este tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil Mac Book Pro 17″ (2,6 Ghz Intel Core
    i7, 8 GB
    DDR3)
  • Sistema Operativo: Mac OS X Snow Leopard 10.6.4
  • Spring 3.0.4
  • Maven 2.2.1
  • Eclipse 3.6 (Helios) con M2Eclipse y Spring IDE

2. Introducción

Mybatis (antes conocido como Ibatis) es una herramienta de persistencia que se encarga de mapear sentencias SQL con clases específicas de nuestro proyecto, pero no es un ORM, ya que no pretende realizar un mapeo entre un modelo de objetos y un modelo relacional, sino mapear sentencias específicas con objetos específicos.

Esta herramienta es especialmente adecuada en los casos en los que la solución no se adapta del todo bien a un ORM como JPA o Hibernate. Por ejemplo:

  • Cuando nos tenemos que ajustar a una base de datos ya definida.
  • Cuando la base de datos hace uso intensivo de procedimientos almacenados.
  • Cuando queremos tener un control total sobre las sentencias SQL que se están lanzando.
  • Cuando nos parece demasiado complicado Hibernate y nos liamos con el mapeo de relaciones.

Se puede decir que esta herramienta es una solución que está por encima de hacerlo directamente con JDBC, dado que reduce considerablemente el número de líneas de código y libera al programador de la responsabilidad de abrir y cerrar la sesión.

Además soporta el uso de cachés declarativas como: OSCache, EHCache, … y si utilizamos estrictamente SQL estándar podemos cambiar de una base de datos a otra sin tocar una línea de código compilado.

Todo esto hace que sea una herramienta bastante intuitiva y cómoda de utilizar que se integra a la perfección con Maven y con Spring permitiendo simplificar el proceso de configuración y crear un código muy limpio.

Por último, indicar que existe una versión para Java y para .NET.

3. Vamos al lío

En este tutorial vamos a ver como integrar Mybatis en un proyecto de Maven manejado con Spring, como el vimos en el tutorial Librería de acceso a datos con Spring y JPA, los alumnos más aventajados pueden intentar integrar Mybatis en el proyecto de JPA para utilizar una u otra solución. Incluso veréis que el objetivo va a ser el mismo trabajar contra una tabla de una base de datos PostgreSQL llamada «persona».

Si ya contamos con un proyecto de Maven lo primero que tenemos que hacer es añadir las siguientes dependencias:

<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.0.4</version>
</dependency>
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
	<version>1.0.0</version>
</dependency>

Con el fin de no trabajar directamente con el API de Mybatis vamos a integrarlo con Spring. Para ello creamos un fichero application-context.xml con el siguiente contenido:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
	default-autowire="byName">

	<context:annotation-config />

	<context:component-scan base-package="com.autentia.tutoriales" />

	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<tx:annotation-driven />

	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="mapperLocations"
			value="classpath:com/autentia/tutoriales/dao/imp/mybatis/**/*.xml" />
		<property name="dataSource" ref="dataSource" />
		<property name="transactionFactory" ref="springManagedTransactionFactory" />
	</bean>

	<bean class="org.mybatis.spring.transaction.SpringManagedTransactionFactory"
		id="springManagedTransactionFactory">
		<constructor-arg index="0" ref="dataSource" />
	</bean>
	
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.postgresql.Driver" />
		<property name="url" value="jdbc:postgresql:tutoriales" />
		<property name="username" value="postgres" />
		<property name="password" value="autentia" />
	</bean>

<!-- A partir de este punto ponemos la definición de las interfaces mappers-->
	<bean id="personaMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
		<property name="mapperInterface" value="com.autentia.tutoriales.dao.PersonaMapper" />
		<property name="sqlSessionFactory" ref="sqlSessionFactory" />
	</bean>

</beans>

De esta definición los puntos más importantes son la definición de la propiedad “mapperLocations” apuntando a la URL donde vamos a encontrar los ficheros XML que almacenan las sentencias SQL que se va a lanzar a para una determinada entidad; y la definición de los mappers que ilustramos con la creación del bean “personaMapper” que define la propiedad “mapperInterface” apuntando a la interfaz que va a definir los métodos de acceso a datos que va a tener una determinada entidad.

El siguiente paso será crear la interfaz definida como “com.autentia.tutoriales.dao.PersonaMapper” donde vamos a definir cuales son las operaciones que se permiten realizar contra la entidad “Persona” tiene el siguiente contenido:

package com.autentia.tutoriales.dao;

import java.util.List;

import com.autentia.tutoriales.model.Persona;

public interface PersonaMapper {

	List<Persona> getAll();

	Persona findByPK(Long idPersona);

	void update(Persona persona);

	void remove(Persona persona);

	void insert(Persona persona);

}

Ahora tenemos que añadir las sentencias que se van a ejecutar por cada una de estas operaciones. Para ello, creamos un fichero PersonaMapper.xml dentro de la ruta que especificamos en la propiedad “mapperLocations”, con el siguiente contenido:

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.autentia.tutoriales.dao.PersonaMapper">
	<select id="findByPK" resultType="com.autentia.tutoriales.model.Persona"
		parameterType="long">
		select * from persona where id_persona=#{id}
	</select>
	<select id="getAll" resultType="com.autentia.tutoriales.model.Persona">
		select * from persona
	</select>
	<insert id="insert" parameterType="com.autentia.tutoriales.model.Persona">
		<selectKey order="BEFORE" keyProperty="idPersona" resultType="long">
			SELECT nextVal('persona_sequence')
		</selectKey>
		insert into persona
		(id_persona,apellidos,direccion,nombre)
		values
		(#{idPersona},#{apellidos},#{direccion},#{nombre})
	</insert>
	<update id="update" parameterType="com.autentia.tutoriales.model.Persona">
		update persona set
		apellidos = #{apellidos},
		direccion = #{direccion},
		nombre = #{nombre}
		where id_persona = #{idPersona}
	</update>
	<delete id="remove" parameterType="com.autentia.tutoriales.model.Persona">
		delete from persona where id_persona = #{idPersona}
    </delete>
</mapper>

Esto ya es puramente Mybatis, definimos que sentencia SQL se tiene que ejecutar para implementar la operación correspondiente. Cabe destacar la forma en la que Mybatis hace uso de las secuencias para establecer un valor autonumérico a través de la etiqueta , la sintaxis de la sentencia de ejecución de la secuencia dependerá de la base de datos que estemos utilizando.

Por último, señalar la importancia de que el nombre del namespace coincida exactamente con la ruta completa de la interfaz que define los métodos.

Para probar el resultado vamos a crear una clase de test que pruebe todas las operaciones que se pueden realizar, el contenido de este test podría ser el siguiente:

package com.autentia.tutoriales.dao.imp.jpa;

import static org.junit.Assert.*;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import com.autentia.tutoriales.dao.PersonaMapper;
import com.autentia.tutoriales.model.Persona;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/application-context-mybatis.xml" })
@Transactional
@TransactionConfiguration(defaultRollback = false)
public class PersonaDAOMybatisImplTest {

	@Resource
	PersonaMapper personaMapper;

	@Test
	public void crudPersona() {

		long sizeInitial = personaMapper.getAll(Persona.class).size();

		Persona persona = new Persona();
		persona.setNombre("Rubén");
		persona.setApellidos("Aguilera Díaz-Heredero");
		persona.setDireccion("Calle de la zarzuela, 45");
		personaMapper.insert(persona);

		assertEquals(sizeInitial + 1, personaMapper.getAll(Persona.class).size());

		assertEquals("Rubén", personaMapper.findByPK(persona.getIdPersona()).getNombre());

		persona.setNombre("Pepe");
		personaMapper.update(persona);

		assertEquals("Pepe", personaMapper.findByPK(persona.getIdPersona()).getNombre());

		personaMapper.remove(persona);

		assertEquals(sizeInitial, personaMapper.getAll(Persona.class).size());

	}

}

Lo importante es como cargamos el fichero application-context.xml correspondiente para levantar el contexto de Spring y como utilizamos la anotación @Resource para inyectar la dependencia de personaMapper que va a contener los métodos antes definidos e implementados.

Como se puede apreciar el código que generamos es de lo más limpio y no hace ninguna referencia al API de Mybatis.

Ahora tendremos que aplicar los mismos conceptos para ir mapeando el resto de entidades o tablas de nuestro dominio de negocio.

4. Conclusiones

Como veis tampoco es muy complicado trabajar con esta herramienta, y desde luego que si los ORM son un dolor de cabeza para vosotros esta es mejor opción que hacerlo directamente con JDBC.

Saludos.

5 COMENTARIOS

  1. Buen aporte compañero pero tengo una duda con la siguiente linea
    import com.autentia.tutoriales.model.Persona;

    ¿De donde proviene y como funciona?

    Saludos

    • Hola Edgardo, permiteme contestarte esa pregunta, es la clase Persona que viene del modelo, es decir tu clase que contiene tus métodos getter y setter

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