5.1. Configuración#
El primer paso es saber cómo configurar nuestro proyecto para poder usar la especificación JPA. Necesitamos dos cosas:
Importar librerías.
Crear una configuración.
5.1.1. Dependencias#
<properties>
<maven.compiler.release>21</maven.compiler.release>
<hibernate.version>7.2.0.Final</hibernate.version>
</properties>
<!-- ... -->
<dependencies>
<!-- Especificación JPA -->
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</dependency>
<!-- Implementación de Hibernate para la especificación anterior -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Driver JDBC para SQLite -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.51.1.0</version>
<scope>runtime</scope>
</dependency>
<!-- Soporte en Hibernate para SQLite -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-community-dialects</artifactId>
<version>${hibernate.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Opcional para anotaciones de comprobación -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.1.1</version>
</dependency>
<!-- Implementación de Hibernate para la especificación anterior -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>9.1.0.Final</version>
<scope>runtime</scope>
</dependency>
<!-- Opcional para evaluación dinámica de cadenas de texto (puede necesitarlo Hibernate Validator) -->
<dependency>
<groupId>org.glassfish.expressly</groupId>
<artifactId>expressly</artifactId>
<version>6.0.0</version>
<scope>runtime</scope>
</dependency>
</dependencies>
En resumidas cuentas es:
El soporte para JPA que proporciona Hibernate mediante hibernate-core. Podemos incluir explícitamente , aunque no es necesario, la especificación jakarta.persistence-api (con la prevención que más adelante se refiere).
Como en nuestro caso particular utilizaremos SQLite, necesitamos el driver JDBC correspondiente (sqlite-jdbc), y el soporte para Hibernate (hibernate-community-dialects).
En principio, basta con lo anterior, pero si se quiere llevar a cabo comprobaciones sobre los valores de los datos (p.ej. las referidas más adelante), será necesaria la implementación para la especificación JPA que proporciona Hibernate, esto es, hibernate-validator. Como anteriormente, podemos incluir explícitamente la implementación (jakarta.validation-api).
La última dependencia (expressly) sólo es necesaria si se utilizan anotaciones implementadas por hibernate-validator que aprovechan la evaluación dinámica de cadenas. Por ejemplo:
@Min(value = 18, message = "La edad debe ser mayor a {value} años") private int edad;
Prudencia
Obsérvense los scopes de las dependencias. Como nuestra intención
es ceñirnos estrictamente a la especificación JPA, las implementaciones de
Hibernate están en el scope runtime (véase el comentario al
respecto que se hizo sobre sqlite-jdbc). Ahora bien, si se
prefiere prescindir de hacer explícita la dependencia a las especificaciones
JPA, entonces el scope de las librerías de Hibernate deberá ser
compile (o no poner ninguno, que es equivalente), porque, de mantenerlo
como runtime, Maven resolverá la dependencia de las
especificaciones también con ese scope y no las tendremos disponibles en la
compilación de la API.
5.1.2. Configuración de la persistencia#
Debe escribirse en el archivo resources/META-INF/persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="3.0"
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">
<!-- Nombre de la unidad de persistencia -->
<persistence-unit name="MiUnidadP" transaction-type="RESOURCE_LOCAL">
<!-- Proveedor de JPA (Hibernate) -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- Entidades (deberían autodetectarse si están anotadas con @Entity) -->
<class>edu.acceso.ejemplo.modelo.MiClase</class>
<!-- Más clases ... -->
<properties>
<!-- Propiedades generales (conexión a la base de datos) -->
<property name="jakarta.persistence.jdbc.driver" value="org.sqlite.JDBC"/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:sqlite:file::memory:"/>
<!-- Innecesarios para SQLite -->
<property name="jakarta.persistence.jdbc.user" value=""/>
<property name="jakarta.persistence.jdbc.password" value=""/>
<!-- Configuración propia de Hibernate -->
<property name="hibernate.dialect" value="org.hibernate.community.dialect.SQLiteDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
</properties>
</persistence-unit>
</persistence>
En este archivo:
Debemos recordar el nombre que le damos a la unidad de persistencia, porque la usaremos luego; y hay propiedades cuyos valores dependen del ORM y el SGBD utilizados.
El proveedor indica cuál es la implementación JPA que usaremos. Algunos muy usados son:
Proveedor
Hibernate
org.hibernate.jpa.HibernatePersistenceProvider
EclipseLink
org.eclipse.persistence.jpa.PersistenceProvider
OpenJPA
org.apache.openjpa.persistence.PersistenceProviderImpl
BatooJPA
org.batoo.jpa.persistence.PersistenceProviderImpl
En caso de que no se detecten, se pueden registrar las clases del modelo cuyos objetos se quieren hacer persistentes.
La url, el driver y dialecto específico dependen de cuál sea el SGBD que utilicemos. La enumeración de los más utilizados la tenemos en una tabla de la unidad anterior, pero necesitamos añadir a ella cómo se llaman los dialectos específicos de Hibernate:
SGBD
Dialecto
SQLite
org.hibernate.community.dialect.SQLiteDialect[1]
MariaDB
org.hibernate.dialect.MariaDBDialect
MySQL
org.hibernate.dialect.MySQLDialect
PostgreSQL
org.hibernate.dialect.PostgreSQLDialect
Oracle
org.hibernate.dialect.OracleDialect
SQL Server
org.hibernate.dialect.SQLServerDialect
La propiedad
hibernate.hbm2ddl.autodefine cómo actuará la aplicación al comparar el esquema definido en las clases con el existente en la base de datos, y puede tener cuatro valores:Valor
Descripción
Efecto
Sin esquema previo
Con esquema previo
none
No hace nada
-
-
validate
Comprueba el esquema
Error
Error si no son iguales
update
Actualiza el esquema
Crea el esquema
Actualiza y conserva datos
create
Crea el esquema
Crea el esquema
Lo crea de nuevo (pérdida de datos)
create-drop
Crea el esquema y lo desecha al cerrar.
Como el anterior en ambos casos, pero se pierde todo al cerrar la sesión de Hibernate.
Las tres últimas propiedades se refieren al registro y son útiles a efectos de depuración: se registran las sentencias SQL que genera el ORM (en el nivel DEBUG), tales sentencias se formatean para que resulten más legibles y, además, se acompañan de comentarios.
Ahora bien, ¿qué ocurre cuándo los datos de conexión o el tipo de base de datos no están definidos de antemano, sino que se definen en tiempo de ejecución? En ese caso, puede definirse un java.util.HashMap que defina las valores de las propiedades y pasar el mapa cuando se usa la unidad de persistencia para crear el objeto EntityManagerFactory (véase a continuación cómo conectar). En ese caso, las definiciones del mapa sobrescribirán a las que pudieran existir en el archivo. Por ejemplo:
Map<String, String> props = new HashMap<>();
props.put("jakarta.persistence.jdbc.url", "jdbc:sqlite:centro.db");
props.put("hibernate.show_sql", "true");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MiUnidadP", props);
Advertencia
Es necesario que el archivo
META-INF/persistence.xml pase a la compilación, que es lo que debería
ocurrir… a menos que haya usted cambiado ese comportamiento al añadir
una sección resources al archivo pom.xml.
Notas al pie