Curso Jakarta EE 9 (19). JPA con Hibernate (2): Configuración.

logo Jakarta EE

Antes de escribir código, aprenderemos a configurar Jakarta Persistence en WildFly y toda la infraestructura necesaria. El objetivo es probar desde el primer el momento los conceptos que iremos viendo.

>>>> ÍNDICE <<<<

MySQL

Para instalar MySQL, podemos seguir el proceso tradicional y emplear su instalador, o bien los repositorios de cualquier distribución de Linux. No obstante, voy a optar por Docker, lo que nos permitirá, entre otros beneficios, disponer de todas los servidores MySQL que queramos en cada momento sin grandes complicaciones. Esta tarea será pan comido con lo que vimos en los siguientes capítulos.

Vamos a crear una base de datos vacía para nuestro desarrollo del día a día. Es una buena idea registrar un volumen para que los datos no se pierdan si por error borramos el contenedor (estas cosas pasan).

docker volume create personalBudget-mysql-data

No hay que hacer mucho más, pues usaremos la imagen oficial de MySQL 8.0.25 disponible en Docker Hub. Creamos y lanzamos un contenedor (mysql-personalBudget) estableciendo una contraseña para acceder como root y creando una base de datos llamada personal_budget con un usuario asociado budget/budget. ¡Los responsables de la imagen han pensado en todo! Su puerto predeterminado (3306) lo voy a exponer en el 3307 porque tengo instalado otro servidor en mi equipo.

docker run -d -p 3307:3306 --name mysql-personalBudget -e MYSQL_ROOT_PASSWORD=root -e MYSQL_USER=budget -e MYSQL_PASSWORD=budget -e MYSQL_DATABASE=personal_budget -v personalBudget-mysql-data:/var/lib/mysql mysql:8.0.25 --default_authentication_plugin=mysql_native_password

Si no tenemos la imagen completa, se descargarán las capas que nos falten. En total, son unos 500 MB.

Más fácil, imposible. MySQL está operativo y podemos conectarnos. Aconsejo utilizar HeidiSQL (solo para Windows, aunque la uso en Linux con PlayOnLinux) o DBeaver (multiplataforma), ambos gratuitos. La herramienta oficial MySQL WorkBench ofrece utilidades interesantes en lo que respecta a la gestión del servidor, pero me resultan más cómodas las dos anteriores.

Crear la conexión en Heidi SQL es trivial (atención al puerto).

DBeaver es compatible con una gran multitud de bases de datos. Al crear la conexión, seleccionamos MySQL y rellenamos el formulario que se muestra a continuación

Antes de guardar, hay que pulsar Test Connection para que DBeaver descargue el controlador o driver JDBC adecuado si es la primera vez que lo usamos con MySQL.

IntelliJ Ultimate

En este IDE podemos beneficiarnos de su integración con bases de datos y el soporte de JPA. En la vista “Database” (View->Tool Windows), pulsando en “+” seleccionamos el tipo.

IntelliJ MySQL

IntelliJ usará la base de datos para validar la correcta definición de entidades (clases que equivalen a una tabla) y consultas en los proyectos que hagan uso de JPA, circunstancia que detecta de forma automática. Si en la entidad se muestra un error indicando que no se encuentra la tabla, asociamos la base de datos.

IntelliJ cannot resolve table
IntelliJ assign Datasource

Otra ayuda que nos brinda es la posibilidad de trabajar con las bases de datos sin salir del IDE, aunque prefiero utilizar un programa externo específico.

IntelliJ utilidades bases de datos

El fichero persistence.xml

La configuración de JPA se realiza en el fichero /src/main/resources/META-INF/persistence.xml. Lo ordena el estándar, aunque en el mundo Spring no es necesario y quizás en Jakarta EE tampoco lo sea en una versión futura. En este fichero indicamos la fuente de datos (data source y otras propiedades de configuración, tanto de JPA como específicas de Hibernate.

<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence
             https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
             version="3.0">

    <persistence-unit name="persistenceUnit-personalBudget" transaction-type="JTA">
        <jta-data-source>jdbc/personalBudgetDS</jta-data-source>
        <properties>
            <property name="hibernate.dialect"
                      value="org.hibernate.dialect.MySQL8Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.generate_statistics" value="true"/>
        </properties>
    </persistence-unit>

</persistence>

Con persistence-unit le hemos dado nombre a la unidad de persistencia que en última instancia se va a materializar en objetos de tipo EntityManager (gestor de entidades) que permitirán usar JPA.

También se ha definido el tipo de transacciones. Podemos elegir entre

  • JTA (Java Transaction API), capaz de trabajar con múltiples fuentes de datos al mismo tiempo (bases de datos relacionales, colas JMS…). El servidor de aplicaciones se encarga de gestionar las transacciones con gran autonomía y en el código tiraremos de anotaciones. Es la opción predeterminada cuando la aplicación se despliega en un servidor de aplicaciones y la que vamos a utilizar en el curso.
  • RESOURCE_LOCAL se emplea si las transacciones solo se aplican a las operaciones realizadas en la unidad de persistencia. Presenta el gran inconveniente de obligarnos a gestionar las transacciones de forma manual en el código, salvo que trabajemos con Spring.

La fuente de datos se configura en el servidor de aplicaciones siguiendo el estándar JCA (Java Connector Architecture). Aquí se indica su nombre con la etiqueta non-jta-data-source o jta-data-source, en función del tipo de transacciones que hayamos elegido.

En las propiedades, se han configurado cuatro exclusivas de Hibernate.

  • hibernate.dialect. El “dialecto” de SQL que debe usar Hibernate para comunicarse con la base de datos. Lista completa.
  • hibernate.show_sql. Imprime en la salida estándar de Java las sentencias SQL que Hibernate va ejecutando en la base de datos. Es muy útil, pero veremos una alternativa mejor.
  • hibernate.format_sql. El código SQL que genera Hibernate se muestra formateado.
  • hibernate.generate_statistics. Recopila diversas métricas accesibles en la consola de administración de WildFly (Runtime->server-monitor->JPA). Es otra opción que solo usaremos para depurar.
  • hibernate.hbm2ddl.auto. El acrónimo hbm2ddl viene a significar “de Hibernate a DDL (lenguaje de definición de datos)”. Por DDL entendemos las sentencias SQL que definen la propia estructura de datos: tablas, índices, claves, columnas… Con esta opción, indicamos a Hibernate qué estrategia debe aplicar para mantener sincronizado el modelo de datos de la aplicación (clases) con la estructura de la base de datos (tablas). Esta sincronización se lleva a cabo durante el arranque de la aplicación. JPA provee la misma funcionalidad con la propiedad jakarta.persistence.schema-generation.database.action pero con menos opciones. La siguiente tabla muestra la equivalencia y cómo funcionan.
    Hibernate JPA  
    none none No hace nada
    create-only create Crea todo el esquema.
    drop drop Elimina el esquema y no lo crea.
    create drop-and-create Crea siempre el esquema. Si ya existe, lo elimina antes.
    create-drop   Igual que create, pero al cerrarse el EntityManagerFactory se elimina.
    validate   Comprueba que el modelo de entidades es coherente con el esquema de la base de datos. Si no, se lanza una excepción de tipo SchemaManagementException lo que impide que la aplicación arranque.
    update   Intenta mantener siempre la sincronización, creando y actualizado lo que sea necesario

¿Qué alternativa seleccionamos? Mientras desarrollamos, update es la más útil, si bien hay que tener en cuenta que si hay datos es posible que algunas actualizaciones no puedan realizarse porque, por ejemplo, haya que redefinir una columna como no nula y ya existan registros con ese valor vacío. Es la opción que usaremos en el curso.

Para producción o distribución como producto, ninguna, o a lo sumo validate con el fin de asegurar que la aplicación va a usar la versión del esquema correcta. Lo más seguro es proporcionar un script SQL de creación inicial, incluyendo los registros predefinidos, triggers, sentencias check, etc. Cuando llegue el momento de actualizar, se crearán los scripts convenientes para aplicar los cambios producidos entre versiones. Para estos menesteres, recomiendo FlyWay o un producto similar.

WildFly

Controlador JDBC

Indiqué párrafos atrás que la conexión a MySQL la realiza WildFly, y para ello necesita el controlador JDBC. De forma manual, se instala como un módulo con estos pasos; en el próximo capítulo lo haremos mediante comandos.

  • Descargarlo de la web de Oracle. Seleccionamos “Platform Independent” para obtener un fichero comprimido y extraer el que tiene la extensión .jar. Es recomendable usar la versión que coincida con la del servidor MYSQL, en nuestro caso la 8.0.25.
  • Lo copiamos a la carpeta {WILDFLY}/modules/system/layers/base/com/mysql/main.
  • Crear en esa ubicación el fichero module.xml con el siguiente contenido (el nombre del fichero en path debe coincidir con el del .jar).
<module xmlns="urn:jboss:module:1.5" name="com.mysql">
    <resources>
        <resource-root path="mysql-connector-java-8.0.25.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>
  • Por último, se registra el driver en el fichero standalone.xml a través del módulo. ¡Mucha atención a los nombres! Es la típica errata tonta que puede traernos de cabeza.
<drivers>
     <driver name="h2" module="com.h2database.h2">
         <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
     </driver>
	<driver name="mysql" module="com.mysql">
	    <driver-class>com.mysql.cj.jdbc.Driver</driver-class>
    </driver>
</drivers>
Fuente de datos con pool de conexiones

La fuente de datos personalBudgetDS se define en WildFly como un “pool de conexiones” y se recupera en la aplicación con el protocolo JNDI. Este “pool” es un conjunto de conexiones con la base de datos que se mantienen abiertas a la espera de ser solicitadas. Cuando un cliente del pool requiere una conexión, se obtiene una de las que no están en uso. Si no hay ninguna libre, el pool crece con nuevas conexiones. Si ya alcanzó su tamaño máximo, se devolverá un error tras un periodo de espera o timeout. Cuando el cliente no necesite la conexión, debe retornarla al pool.

La idea es mejorar el rendimiento al evitarse que cada vez que la aplicación quiera lanzar sentencias SQL tenga que asumir el coste de abrir y cerrar una nueva conexión. Asimismo, podemos limitar el número de conexiones simultáneas y analizar el uso de la aplicación.

El funcionamiento del pool parece complejo, pero como programadores no tenemos que preocuparnos a la hora de usarlo: JPA\Hibernate se encargará de la obtención y liberación de las conexiones de forma automática. Incluso si obtenemos directamente una conexión modelada con la interfaz DataSource de JDBC -lo haremos en breve- su método close no la cerrará sino que la devolverá al pool. En este último caso de uso, es vital asegurarnos de que las conexiones se liberan para evitar que queden “atrapadas” en nuestro código y no puedan ser reutilizadas.

Lo que sí es importante es la configuración. Debemos definir el tamaño del pool entre un mínimo y un máximo; el tiempo que puede permanecer una conexión en espera sin que se utilice también es configurable. La elección de estos parámetros depende de cada aplicación en concreto y la carga de trabajo que soporte. Y no perdamos de vista que las conexiones consumen memoria tanto en el servidor de aplicaciones como, sobre todo, en el servidor de bases de datos. De este último también conviene tener unas nociones básicas acerca de su funcionamiento para ajustarlo. Por ejemplo, MySQL de forma predeterminada admite 150 conexiones concurrentes (variable max_connections).

Contamos con las siguientes propiedades.

min-pool-size0La cantidad de conexiones que el pool tendrá como mínimo.
max-pool-size20El número máximo de conexiones que puede albergar el pool. Una vez superado, ya no se obtendrán más conexiones.
idle-timeout-minutesinfinitoEl tiempo máximo de vida de una conexión en el pool sin ser utilizada.
initial-pool-size0Las conexiones que debe contener el pool cuando se inicie.

Hay varias maneras de definir la fuente de datos.

  • En el fichero de configuración del servidor standalone.xml, justo en el mismo sitio que hemos puesto el controlador.
 <datasources>
        <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
          <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
                    <driver>h2</driver>
                    <security>
                        <user-name>sa</user-name>
                        <password>sa</password>
                    </security>
                </datasource>
				 <datasource jta="false" jndi-name="java:/jdbc/personalBudgetDS" pool-name="personalBudgetDS" enabled="true"
                use-java-context="true" use-ccm="true">
					<connection-url>jdbc:mysql://localhost:3307/personal_budget?autoReconnect=true&amp;useSSL=false</connection-url>
					<driver>mysql</driver>
					<pool>
						<initial-pool-size>1</initial-pool-size>
						<min-pool-size>1</min-pool-size>
						<max-pool-size>5</max-pool-size>
					</pool>
					<security>
						<user-name>budget</user-name>
						<password>budget</password>
					</security>
					<timeout>
						<idle-timeout-minutes>5</idle-timeout-minutes>
					</timeout>
				</datasource>
                <drivers>
                    <driver name="h2" module="com.h2database.h2">
                        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                    </driver>
					<driver name="mysql" module="com.mysql">
						<driver-class>com.mysql.cj.jdbc.Driver</driver-class>
						<xa-datasource-class>com.mysql.cj.jdbc.MysqlXADataSource</xa-datasource-class>
					</driver>
                </drivers>
            </datasources>
  • En la consola de administración -debe estar accesible y con un usuario administrador habilitado- mediante un formulario de tipo asistente. Podemos crearla, modificarla, eliminarla, probar la conectividad…
  • En su propio fichero, un xml con el sufijo -ds.xml. Se pone en {WildFly}/standalone/deployments/personalBudget-ds.xml.
<?xml version="1.0" encoding="UTF-8"?>
<datasources xmlns="http://www.jboss.org/ironjacamar/schema">
    <datasource jta="false" jndi-name="java:/jdbc/personalBudgetDS" pool-name="personalBudgetDS" enabled="true"
                use-java-context="true" use-ccm="true">
        <connection-url>jdbc:mysql://localhost:3307/personal_budget?autoReconnect=true&amp;useSSL=false&amp;allowPublicKeyRetrieval=true</connection-url>
        <driver>mysql</driver>
        <pool>
            <initial-pool-size>1</initial-pool-size>
            <min-pool-size>1</min-pool-size>
            <max-pool-size>5</max-pool-size>
        </pool>
        <security>
            <user-name>budget</user-name>
            <password>budget</password>
        </security>
        <timeout>
            <idle-timeout-minutes>5</idle-timeout-minutes>
        </timeout>
    </datasource>
</datasources>

Funciona, pero no es aconsejable por este warning (aunque lo cierto es que WildFly lo muestra desde hace años y de momento es inofensivo).

WARN  [org.jboss.as.connector] (MSC service thread 1-5) WFLYJCA0091: -ds.xml file deployments are deprecated. Support may be removed in a future version.

Además, con este método no resulta posible modificar la fuente de datos con la consola de administración o la interfaz para la línea de comandos (CLI).

  • El anterior fichero también se puede empaquetar en el artefacto del proyecto si lo ubicamos en la ruta /src/main/webapp/WEB-INF/.
  • Con la interfaz de administración de línea de comandos (CLI). Lo haremos en el próximo capítulo cuando hablemos de Docker.
Bitácora de Hibernate

Conocer las sentencias SQL ejecutadas por Hibernate es fundamental para saber si lo estamos usando correctamente y detectar problemas de rendimiento antes de que sea demasiado tarde. Además, usaré esta información para demostrar su funcionamiento.

Podemos verlas habilitando el “flag” hibernate.show_sql, pero el texto que se imprime no indica los parámetros. Además, se envía a la salida estándar y deberíamos usar el sistema de bitácora o logs de WildFly. Lo mejor es activar las siguientes trazas.

  • org.hibernate.SQL -> DEBUG
  • org.hibernate.type.descriptor.sql -> TRACE

Añadimos las dos categorías correspondientes al subsistema de logging tal y como vimos en su momento. Con CLI, estos son los comandos.

/subsystem=logging/logger=org.hibernate.SQL:add
/subsystem=logging/logger=org.hibernate.SQL:write-attribute(name="level", value="DEBUG") 

/subsystem=logging/logger=org.hibernate.type.descriptor.sql:add
/subsystem=logging/logger=org.hibernate.type.descriptor.sql:write-attribute(name="level", value="TRACE") 

/subsystem=logging/console-handler=CONSOLE:write-attribute(name="level", value="TRACE")

Veremos algo como lo que sigue.

16:12:37,946 DEBUG [org.hibernate.SQL] (default task-1) 
    select
        usernatura0_.id as id1_0_0_,
        usernatura0_.number as number2_0_0_ 
    from
        users_naturalid usernatura0_ 
    where
        usernatura0_.id=?
16:12:37,946 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-1) binding parameter [1] as [BIGINT] - [1]
16:12:37,947 TRACE [org.hibernate.type.descriptor.sql.BasicExtractor] (default task-1) extracted value ([number2_0_0_] : [INTEGER]) - [234]

Probando…

Arranquemos WildFly, con MySQL en funcionamiento, sin ningún despliegue. En la salida, buscamos las trazas que indican la disponibilidad de la fuente de datos.

 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-4) WFLYJCA0001: Bound data source [java:jboss/datasources/ExampleDS]

Si no hay conexión con MySQL, lo sabremos en el acto gracias a esta advertencia.

20:10:57,801 WARN  [org.jboss.jca.core.connectionmanager.pool.strategy.OnePool] (JCA PoolFiller) IJ000610: Unable to fill pool: java:/jdbc/personalBudgetDS: jakarta.resource.ResourceException: IJ031084: Unable to create connection
	
Caused by: java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
	
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure

Vamos a escribir un poquito de código para ver cómo usar la fuente de datos. Creamos un proyecto Jakarta EE llamado jpa-entity que vamos a reutilizar y ampliar en los próximos capítulos. De inicio, contará con un servlet muy parecido al de nuestro viejo amigo el proyecto hello.

package com.danielme.jakartaee.jpa.servlets;

import com.danielme.jakartaee.jpa.db.DbInfo;
import jakarta.inject.Inject;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/infoServlet")
public class InfoServlet extends HttpServlet {

    @Inject
    DbInfo dbInfo;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        PrintWriter printWriter = response.getWriter();
        response.setContentType("text/plain;charset=UTF-8");
        printWriter.print(dbInfo.getVersion());
    }

}

Inyectamos un objeto de esta clase.

package com.danielme.jakartaee.jpa.db;

import jakarta.annotation.Resource;
import jakarta.enterprise.context.ApplicationScoped;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@ApplicationScoped
public class DbInfo {

    @Resource(lookup = "java:/jdbc/personalBudgetDS")
    DataSource dataSource;

    public String getVersion() {
        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement("SELECT VERSION()");) {
            ResultSet resultSet = ps.executeQuery();
            resultSet.next();
            return resultSet.getString(1);
        } catch (SQLException ex) {
            return ex.getMessage();
        }
    }
}

El método getVersion() retorna la versión de MySQL usando una consulta. Su código se parece al del ejemplo de JDBC del capítulo anterior. Lo relevante es la obtención de la fuente de datos: se inyecta una instancia de DataSource a partir del nombre JNDI. Esto también le resultará familiar al lector, pues lo vimos en el capítulo CDI – Productores.

Ahora ya podemos desplegar la aplicación de ejemplo utilizando cualquiera de las técnicas presentadas en el capítulo tres. Si todo va bien, la dirección http://localhost:8080/jpa-entity/infoServlet devolverá la versión de MySQL.

Hemos usado la fuente de datos de forma “manual”, pero ¿qué hay de JPA? En el proyecto se encuentra, entre otras, esta clase.

package com.danielme.jakartaee.jpa.entities;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.math.BigDecimal;
import java.time.LocalDate;

@Entity
@Table(name = "expenses")
@Getter
@Setter
public class Expense {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

Habría mucho que explicar acerca de este código, pero, de momento, es suficiente con saber que una clase de tipo @Entity equivale a una tabla de la base de datos. Dado que en el persistence.xml Hibernate está en modo update, la primera vez que se desplegó el proyecto se creó la tabla mágicamente. Si la borramos y volvemos a desplegar la aplicación, aparecerá otra vez. En la bitácora vemos algo así.

20:25:42,651 INFO  [stdout] (ServerService Thread Pool -- 76) Hibernate: create table expenses (id bigint not null auto_increment, primary key (id)) engine=InnoDB

@DataSourceDefinition

La especificación Jakarta Annotations recoge una forma para declarar fuentes de datos utilizando esta anotación y registrarla con JNDI. Se pueden declarar varias de una tacada con @DataSourceDefinitions.

package com.danielme.jakartaee.jpa.db;

import jakarta.annotation.sql.DataSourceDefinition;

@DataSourceDefinition(
        className = "com.mysql.cj.jdbc.MysqlConnectionPoolDataSource",
        name = "java:/jdbc/personalBudgetAnnotation",
        serverName = "localhost",
        databaseName = "personal_budget",
        portNumber = 3307,
        user = "budget",
        password = "budget",
        initialPoolSize = 1,
        minPoolSize = 1,
        maxPoolSize = 5,
        maxIdleTime = 300
)
public class DataSourceConfiguration {
}

Es una fuente de datos equivalente a la que hemos creado en el servidor. Necesitamos en el classpath de nuestra aplicación la librería con el controlador JDBC porque hacemos referencia a una de sus clases en className. Lo primero que se nos puede venir a la cabeza es incluirla como dependencia en el pom. Pero WildFly permite configurar el classpath de las aplicaciones que despliega, de tal modo que se pueden hacer visibles las librerías del servidor a cualquiera de ellas. Es lo que nos interesa, así que vamos a añadir al proyecto la dependencia del controlador con este fichero de configuración (/src/main/webapp/WEB-INF/jboss-deployment-structure.xml).

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="com.mysql" export="true"/>
        </dependencies>
    </deployment>
</jboss-deployment-structure>

Hemos importado en el proyecto el módulo com.mysql y ya se puede crear sin errores la nueva fuente de datos personalBudgetAnnotation. Es exclusiva del proyecto y no aparecerá en la consola de administración.

Nota: también es posible excluir del classpath de la aplicación librerias del servidor. Esto permite que un artefacto empaquete versiones distintas de las librerias que incluye WildFly. No lo veremos en el curso, pero aprovecho para remitir a este enlace.

API de Hibernate

Hasta ahora, no hemos tocado el pom. Las dependencias de JPA las tenemos dentro de las APIs de Jakarta EE y para usar la especificación no necesitamos nada más. Esto cambia si queremos emplear características propias de Hibernate porque tendremos que hacer accesibles sus librerías en nuestro proyecto. Lo siguiente es válido.

 <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <scope>provided</scope>
            <version>5.3.20.Final</version>
</dependency>

El módulo hibernate-core se encuentra en WildFly, así que lo importamos como provided. La versión 5.3.20.Final es la que incluye WildFly 22, pero a medida que vayamos actualizando el servidor tendremos que estar atento para cambiarla y usar la correcta. Esta acción es más sencilla y segura si en vez de hacerla a mano recurrimos al bom de WildFly, un pom especial en el que se declaran las librerías del servidor según su versión. Es la estrategia ya explicada en el capítulo 4 para usar Slf4j.

 <dependencyManagement>
      <dependencies>
          <dependency>
              <groupId>org.wildfly.bom</groupId>
              <artifactId>wildfly-jakartaee8-with-tools</artifactId>
              <scope>import</scope>
              <type>pom</type>
              <version>22.0.0.Final</version>
          </dependency>
      </dependencies>
 </dependencyManagement>

<dependencies>
        <!-- wildfly bom version-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <scope>provided</scope>
        </dependency>

Ahora, la versión de hibernate-core es la establecida en el bom. Ya no tenemos que averiguar y revisar cual es la que empaqueta el servidor, simplemente nos aseguramos de explicitar siempre el bom adecuado.

Tal y como se aprecia en el ejemplo, no está todavía disponible el bom para las versiones Preview de WildFly que son las compatibles con Jakarta EE 9. No es un gran problema dado que la aplicación cuando se despliegue usará las librerías del servidor, pero sí podemos encontrar algunas dificultades derivadas del cambio del nombre de los paquetes de javax a jakarta. En concreto, con Hibernate he tenido que añadir la siguiente dependencia para que compilen las pruebas del proyecto de ejemplo.

 <dependency>
        <groupId>javax.persistence</groupId>
        <artifactId>javax.persistence-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
 </dependency>

Monitorizando el pool de conexiones

El pool que hemos configurado en este capítulo tiene unos valores un tanto arbitrarios que en teoría deberían ser suficientes para desarrollar una aplicación web típica de gestión. La situación cambiará cuando la aplicación se ejecute en el entorno de explotación final y los usuarios pasen a disfrutarla.

WildFly permite monitorizar el comportamiento del pool desde la consola. En la sección Runtime están nuestras fuentes de datos. También podemos “purgar” las conexiones abiertas o en espera.

Las estadísticas deben estar activadas (de forma predeterminada no lo están). Esto se hace pulsando el botón “Enable Statistics” o en la configuración de la fuente con la propiedad statistics-enabled

--max-pool-size=5 --statistics-enabled=true 

Una vez activadas, hay que reiniciar el servidor, acción que podemos realizar también desde esa misma pantalla. Sea como fuere, podremos ver las conexiones que hay en el pool y el número total de ellas que han sido usadas.

Las estadísticas completas están disponibles en CLI con la siguiente orden.

/subsystem=datasources/data-source=personal_budgetDS/statistics=pool:read-resource(include-runtime=true)

En MySQL, las conexiones abiertas se muestran con esta consulta.

SHOW PROCESSLIST

Código de ejemplo

El código de ejemplo del capítulo se encuentra en GitHub (todos los proyectos son independientes pero están en un único repositorio). Para más información sobre cómo utilizar GitHub, consultar este artículo.

>>>> ÍNDICE <<<<

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios .