En Quarkus podemos conectarnos con bases de datos usando una conexión JPA estandar, como ocurre con otros frameworks Java. De este modo, podremos hacer que nuestra API persista datos en una base de datos, y que luego los podamos recuperar. Si conocemos JPA, le podemos sacar mucho partido.
Quarkus utiliza Panache ORM. Se trata de una biblioteca de clases específicamente diseñada para Quarkus que se levanta por encima de Hibernate ORM. Esto significa que, si bien Quarkus realmente está usando Hibernate ORM, en la mayoría de casos no tendremos que interactuar con Hibernate ORM, sino usar las clases que trae Panache y que se asemejan más a lo que otras alternativas como Spring Data hacen. Por ejemplo, lejos de configurar un EntityManager manualmente, podremos usar repositorios, igual que podemos hacer en Spring.
Además, Panache ORM es compatible con otras dos técnicas de programación:
- Por un lado, podemos usar el patrón ActiveRecord. Con esto lo que conseguimos es que nuestras clases de datos tengan métodos como
save(),update()odelete(). Para gente que venga de otros frameworks como Ruby on Rails, Django o Laravel, trabajar con patrón ActiveRecord le resultará familiar, puesto que las instancias de nuestros modelos de datos se ocuparán de persistirse a sí mismas, actualizarse o borrarse, además de métodos estáticos para buscar y filtrar elementos. - Por otro lado, la programación reactiva continúa cogiendo fuerza. Quarkus tiene soporte para programación reactiva gracias a Vert.x, y Panache tiene la capacidad de ser usado para acceder de forma reactiva a datos. En líneas generales, permite aplicar principios pubsub a nuestros endpoints para que los hilos que manejan las peticiones se dispersen mejor mientras el servidor está esperando a que la base de datos responda, mejorando el throughtput de la aplicación.
Agregar las extensiones
Para configurar el soporte para Panache ORM y acceder a bases de datos, primero tendremos que asegurarnos de configurar los siguientes plugins. Esto lo podemos hacer al crear un proyecto, o bien lo podemos hacer a posteriori usando quarkus-cli o el plugin para Maven o Gradle de Quarkus:
- Necesitaremos agregar la extensión
quarkus-hibernate-orm-panache, que es la que agrega el soporte para Panache ORM e Hibernate. - También necesitaremos agregar alguna de las extensiones que portan el driver JDBC. Con Hibernate-ORM-Panache agregamos el soporte para JPA, pero es importante tener un driver JDBC porque es a lo que JPA traduce sus queries y sus sentencias SQL. Según nuestra base de datos, podremos instalar una u otra:
- H2:
quarkus-jdbc-h2 - MariaDB:
quarkus-jdbc-mariadb - MySQL:
quarkus-jdbc-mysql - PostgreSQL:
quarkus-jdbc-postgresql - Microsoft SQL Server:
quarkus-jdbc-mssql - Oracle DB:
quarkus-jdbc-oracle
- H2:
Configuración en el application.properties
Una vez hecho eso, tendré que configurar el acceso a base de datos. En tiempo de desarrollo, la forma más simple es modificar el archivo src/main/resources/application.properties, que inicialmente estará en blanco pero que podemos rellenar con los campos que queramos asociar con la conexión.
Lo que haremos en este archivo es declarar varios parámetros de configuración. Si es la primera vez que defines este tipo de archivos, tienen nombres un poco largos. Lo importante es que después del símbolo de igual se especificará el valor de la variable:
quarkus.datasource.db-kind=h2
quarkus.datasource.jdbc.url=jdbc:h2:./db
quarkus.hibernate-orm.database.generation=update
La primera configuración es quarkus.datasource.db-kind y se usa para indicar el tipo de driver que necesitamos. Por ejemplo, en este caso estoy poniendo h2, pero si fuese de otro tipo, la podría poner cambiandolo por el tipo de driver, como puede ser mysql, mariadb o postgresql.
La segunda configuración es quarkus.datasource.jdbc.url y se usa para especificar la ruta de conexión JDBC. Por ejemplo, en mi caso especifico que la ruta es jdbc:h2:./db. El parámetro a poner aquí depende de cada tipo de driver, así que si estás usando otro proveedor de bases de datos, conviene que consultes la documentación de su driver JDBC para saber cómo se debe declarar la configuración.
El último parámetro es quarkus.hibernate-orm.database.generation. Hibernate puede generar tablas cuando se levanta la aplicación si hace falta. Escaneará las anotaciones JPA que pongamos a las entidades y se asegurará de que la base de datos se corresponda con lo especificado. Por ejemplo, si declaramos un modelo llamado Libro se asegurará de que exista una tabla llamada Libro. Muchos tutoriales aquí especifican como valor drop-and-create, pero eso hace que la base de datos se reinicie de cero cada vez que se reinicia la aplicación. Si bien eso se asegura de que el modelo sea óptimo, para poder ser más dinámicos a la hora de probar la aplicación yo lo voy a cambiar por update. De este modo, mientras no se cambie el modelo de datos, se reutilizará la base de datos. En caso de agregar o quitar columnas o entidades, al arrancar la aplicación Hibernate lanzará un conjunto de sentencias DDL como CREATE TABLE o ALTER TABLE para dejar el esquema de datos actualizado.
Igualmente, cuando ejecutemos la aplicación en modo producción no deberíamos dejar que Hibernate se ocupe de actualizar el modelo de datos. En su lugar, deberíamos hacerlo por fuera, o utilizar una tecnología como Flyway o Liquibase para este fin, puesto que este tipo de tecnologías pueden resultar impredecibles para el modelo de datos, especialmente en microservicios donde puede que haya varias versiones de la aplicación corriendo mientras se hace un despliegue.
En este caso no estoy especificando ni usuario ni contraseña porque H2 no entiende de eso. Para establecer una conexión con una base de datos que sí necesite usuario y contraseña, podemos utilizar las propiedades quarkus.datasource.username yquarkus.datasource.password para especificar de manera correspondiente el valor del usuario o el de la contraseña.
En el siguiente ejemplo, me conecto con una base de datos MySQL:
quarkus.datasource.db-kind=mysql
quarkus.datasource.username=root
quarkus.datasource.password=escuela
quarkus.datasource.jdbc.url=jdbc:mysql://localhost:3306/escuela
Y en el siguiente ejemplo, me conecto con una base de datos PostgreSQL:
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=postgres
quarkus.datasource.password=hospital
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/hospital