En este tutorial vamos a ver cómo integrar MyBatis con Spring Boot y como usar la caché de MyBatis sobre Redis.
0. Índice de contenidos
- 1. Introducción
- 2. Entorno
- 3. Integrar MyBatis con Spring Boot
- 4. Uso de la caché de MyBatis con Redis
- 5. Conclusiones
- 6. Referencias
1. Introducción
El objetivo que perseguimos con el presente tutorial, es integrar el uso de MyBatis a través de los
starters de Spring Boot, ya que hasta hace poco, no disponíamos de un starter
dedicado a MyBatis y teníamos que configurarlo de la manera tradicional.
Posteriormente, veremos como usar la caché de segundo nivel que ofrece Mybatis con el soporte de Redis, tenéis más detalles del funcionamiento de la caché
de MyBatis en Caché MyBatis.
2. Entorno
El tutorial está escrito usando el siguiente entorno:
- Hardware: MacBook Pro 15' (2.3 GHz Intel Core i7, 16GB DDR3 SDRAM)
- Sistema Operativo: Mac OS X El Capitan 10.11
- Docker 1.11.1
- Spring Boot 1.3.5
- MyBatis 3.4.0
- mybatis-spring-boot-starter 1.1.1
- Redis 3.2.0
- mybatis-redis-cache 1.0.0-beta2
3. Integrar MyBatis con Spring Boot
Como hemos comentado anteriormente Spring Boot no nos proporciona un starter dedicado a MyBatis y ha sido la gente de MyBatis la que ha desarrollado un starter con el que podemos
integrar y configurar facilmente este framework.
El primer paso que deberíamos realizar es incluir la dependencia en nuestro proyecto
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency>
Como ya habéis podido ver en los diferentes tutoriales publicados sobre MyBatis los elementos fundamentales que hay que configurar para trabajar con MyBatis
son: SqlSessionFactoryBean, SqlSessionFactory, SqlSessionTemplate y los diferentes Mappers.
Repasemos lo que realiza mybatis-spring-boot-starter
- Comprueba la existencia de un DataSource.
- Crea una instancia de SqlSessionFactoryBean, pasandole como argumento el DataSource y que será la encargada de instanciar SqlSessionFactory
- Crea una instancia del SqlSessionTemplate a través del SqlSessionFactory
- Busca los Mappers dentro de nuestra aplicación, les asocia el SqlSessionTemplate y los registra para poder ser inyectados en nuestras clases de negocio.
Como en el resto de starters de Spring Boot podemos añadir una serie de parámetros de configuración dentro del fichero application.properties, usando el prefijo ‘mybatis’
- mybatis.config-location: Localización del fichero mybatis-config.xml.
- mapper-locations: Localización de los ficheros xml que representan a los ‘mappers’.
- type-aliases-package: Paquete donde localizar los ‘alias’ de tipo.
- type-handlers-package: Paquete donde localizar los ‘alias’ de los handlers.
- executor-type: Tipo de ejecutor usado por MyBatis SIMPLE, REUSE, BATCH
Podéis ver los fuentes de este tutorial aquí, de todas formas vamos a repasar los aspectos más importantes:
Nuestro pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.autentia</groupId> <artifactId>spring-boot-mybatis-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>spring-boot-mybatis-demo</name> <description>Demo de la integracion de MyBatis con Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.5.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!-- Starter MyBatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <!-- H2 BBDD --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <!-- Test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
A parte de la dependencia con mybatis-spring-boot-starter, destacamos la dependencia con H2 para crear una BBDD en memoria sobre la que lanzaremos nuestros Test de Integración. Esta BBDD se creará a partir de un fichero *.sql que le indicaremos en el application.properties
Dentro del directorio src/main/resources vamos a incluir el fichero de propiedades application.properties que tendrá el siguiente aspecto:
# Script de Inicialización de BBDD spring.datasource.schema=schema.sql #Fichero de Configuración de MyBatis mybatis.config-location=mybatis-config.xml # Configuración de Logs logging.level.root=WARN logging.level.com.autentia.mappers=TRACE
El parámetro spring.datasource.schema indica el fichero .sql utilizado para crear y poblar la BBDD.
mybatis.config-location como hemos visto anteriormente indica la ubicación del fichero de configuración de MyBatis.
logging.level.root y logging.level.com.autentia.mappers indican el nivel de traza.
El fichero de configuración de MyBatis (mybatis-config.xml)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.autentia.model"/> </typeAliases> <mappers> <mapper resource="com/autentia/mappers/CourseMapper.xml"/> </mappers> </configuration>
Como se puede observar, hemos declarado el fichero xml que define un mapper CourseMapper.xml y un paquete com.autentia.model que se utilizará para
localizar los alias de tipo que usaremos en los mappers.
Vamos a ver el contenido de schema.sql
-- Create Table create table courses (name varchar, credits int); -- Insert data insert into courses (name, credits) values ('Angular 2', 1); insert into courses (name, credits) values ('PrimeFaces', 2);
Este script no presenta mucha complicación simplemente crea una tabla ‘Courses’ y la puebla con 2 registros. Ahora sólo nos falta crear
la infraestructura relativa a los ‘mappers’, en primer lugar creamos la interfaz CourseMapper en la que definimos nuestros métodos de acceso a BBDD:
@Mapper public interface CourseMapper { List getCourses(); }
y el fichero asociado CourseMapper.xml
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.autentia.mappers.CourseMapper"> <select id="getCourses" resultType="Course"> select * from courses </select> </mapper>
En este fichero vincularemos el método getCourses definido en la interfaz con la query select * from courses para devolver objetos de tipo Course.
Para probar el correcto funcionamiento creamos un test de integración CourseMapperIntegrationTest con el siguiente contenido:
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SpringBootMyBatisIntegrationDemo.class) public class CourseMapperIntegrationTest { @Autowired private CourseMapper courseMapper; @Test public void getCourses() throws Exception { List courses = courseMapper.getCourses(); MatcherAssert.assertThat(courses, hasSize(2)); } }
El test comprueba que existen 2 cursos en nuestra BBDD, lo lanzamos desde nuestro IDE y debería pasar sin problemas
Sencillo no???
4. Uso de la caché de MyBatis con Redis
En este apartado vamos a ver como podemos activar la caché de segundo nivel de MyBatis para que use como soporte Redis (todos los detalles sobre la caché
de MyBatis en el tutorial de mi compañero
Jose Luis Caché MyBatis) .
El primer paso es añadir la siguiente dependencia a nuestro pom.xml
<!-- Mybatis Redis Cache --> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-redis</artifactId> <version>1.0.0-beta2</version> </dependency>
El siguiente paso es añadir el soporte de caché a nivel de mapper para que use redis, para ello incluimos lo siguiente en nuestro CourseMapper.xml
<cache type="org.mybatis.caches.redis.RedisCache"/>
Por último creamos el fichero de configuración en el que especificamos la url y puerto de nuestro servidor de Redis
host=192.168.99.100 port=6379
Pero, falta algo no ??? Efectivamente nos falta un servidor de Redis y como siempre Docker aparece al rescate ;).
docker run -d --name redis_cache -p 6379:6379 redis
Este comando levanta un contenedor con redis y expone el puerto 6379 para que podamos acceder a él. Entramos en el contenedor ejecutando lo siguiente:
docker exec -it redis_cache bash
Una vez dentro del contenedor redis, ejecutamos el cliente redis-cli y ejecutamos monitor para activar el monitor de redis, y poder ver las operaciones que se realicen contra él.
Lanzamos la prueba de nuevo y observamos lo que ocurre en el monitor de redis:
Como podemos observar por el monitor, se han realizado 2 operaciones: la primera HGET para ver si la consulta estaba cacheada
en redis y posteriormente una HSET para insertar los valores devueltos por la consulta a BBDD.
Volvemos a ejecutar la consulta:
Como podemos comprobar, se ha realizado únicamente una operación HGET para recuperar los valores de la caché, sin necesidad de acceder a la BBDD. Lo vemos más
claro en los logs que presenta nuestro IDE, en esta ejecución no aparecen los logs relativos a la consulta realizada con MyBatis
5. Conclusiones
Como hemos podido comprobar, Spring Boot, a través de los starters nos facilita enormemente la creación y configuración
de un nuestras aplicaciones, dejándonos más tiempo para centrarnos en las funcionalidades de negocio.
Por otro lado hemos visto lo fácil que resulta la activación de la caché de segundo nivel de MyBatis con el soporte de Redis, esta librería está en versión 1.0.0-beta2
y aún le falta el soporte para RedisCluster, pero por lo que hemos estado viendo en su repo están en ello.
Un saludo.