Configuración de Hibernate mediante Annotated Class

Como ya sabéis, hace algunas semanas estuvimos revisando el procedimiento para elaborar un proyecto Hibernate con configuración XML. Para completar el tema, hoy vamos a tratar de explicar cómo habilitar el framework Hibernate usando como configuración un fichero Properties y la funcionalidad Annotated Class. Esta será la estructura que encontraremos en los proyectos empresariales creados en los últimos 5 años (salvo aquellos que hayan dado ya el salto hacia Spring o Spring Boot), así que será buena idea tener claro cómo se construye una aplicación de este tipo. 



👉 Antes de empezar, unos comentarios. Por si no lo sabéis, diremos que Hibernate es un framework que implementa la especificación JPA (Java Persistence API) y que se emplea en la parte del Backend. Hay que tener en cuenta que tanto Hibernate como JPA facilitan enormemente el desarrollo del software que se encarga de realizar el acceso a la Base de Datos, ya que automatiza parte del complejo proceso que había que implementar hace 20 años con la especificación JDBC (Java Data Base Connectivity). La librería JPA se importa como javax.persistence.* y el framework Hibernate se importa como org.hibernate.*. Por supuesto, aunque Hibernate cubre toda la librería JPA, hay que puntualizar que va más allá e incorpora funcionalidad adicional.

 

Configuración de Hibernate mediante Annotated Class


Pues nada, aclarado lo anterior, vamos a revisar los pasos necesarios para habilitar Hibernate en nuestro proyecto con la configuración Annotated Class. Serían los siguientes.

 

1º) Nos creamos un proyecto Maven simple. En mi caso establezco como paquete base el com.universo.annotated, pero vosotros podéis usar cualquier otro.



2º) Nos vamos al fichero pom.xml y añadimos las dependencias necesarias para descargarnos las librerías asociadas a Hibernate y MySql. El fichero pom.xml debería quedar algo así:


<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 

https://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>com.universo.annotated</groupId>

  <artifactId>HibernateConfigAnnotated</artifactId>

  <version>0.0.1-SNAPSHOT</version>

 

  <!-- Propiedades que van a ser usadas por las dependencias -->

  <properties>

      <hibernate.version>5.4.1.Final</hibernate.version>

  </properties>

 

  <dependencies>

 

      <!-- Dependencias de Hibernate cuyas librerias deben ser descargadas -->

      <dependency>

             <groupId>org.hibernate</groupId>

             <artifactId>hibernate-core</artifactId>

             <version>${hibernate.version}</version>

      </dependency>

 

      <!-- Dependencias de Mysql - Driver JDBC -->

      <dependency>

             <groupId>mysql</groupId>

             <artifactId>mysql-connector-java</artifactId>

             <version>8.0.14</version>

             <scope>runtime</scope>

      </dependency>

 

  </dependencies>

 

</project>

 

3º) Seleccionamos el proyecto y lanzamos la opción MAVEN - UPDATE PROJECT. De este modo, Eclipse se descargará las librerías necesarias para nuestro proyecto. Las Maven Dependencies deberían quedar de este modo.

 

👉 Como se aprecia, ahora nuestro proyecto tiene, entre otras, las siguientes librerías correspondientes a Hibernate, JPA y Mysql:

  • hibernate-core-5.4.1.Final.jar
  • hibernate-commons-annotations-5.1.0.Final.jar
  • javax.persistence-api-2.2.jar
  • mysql-connector-java-8.0.14.jar


4º) A continuación, nos creamos una tabla MySql para probar la conexión proporcionada por Hibernate. Por ejemplo, nos creamos la tabla "valor".


CREATE TABLE `universojava`.`valor` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `nombre` VARCHAR(45) NOT NULL,
  `ticker` VARCHAR(10) NOT NULL,
  `indice` VARCHAR(10) NULL,
  `pais` VARCHAR(20) NULL,
  `rentabilidad` FLOAT NULL,
  PRIMARY KEY (`id`));


5º) Damos de alta algunos registros para que podamos operar con ellos y con eso damos por concluida la incursión en la parte de Base de Datos.


 

Creación de los componentes del proyecto

 

6º) Volvemos ahora a nuestro proyecto Eclipse y pasamos a crear el objeto entidad Valor.java, que nos va a servir para mapear la tabla "valor" que acabamos de crearnos. Esta clase tenemos que definirla con las anotaciones @Entity y @Table.

En cuanto a los atributos de la misma, tenemos que marcarlos con la anotación @Column para asociarlos con la columna correspondiente de la tabla MySql. En cuanto a la Primary Key de la tabla, en nuestra entidad tendremos que marcarla con la anotación @Id.

 

💎 Hay que mencionar que todas las anotaciones anteriores pertenecen a la librería  javax.persistence.* de la especificación JPA.

En definitiva, debería quedarnos algo similar a esto:

 

// ************************************************** 

 package com.universo.annotated.modelo;

 

//Importar Anotaciones de JPA

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

 

@Entity

@Table(name="valor")

public class Valor {

 

      @Id

      @GeneratedValue(strategy = GenerationType.IDENTITY)

      @Column(name="id")

      private Long id;

      @Column(name="nombre")

      private String nombre;

      @Column(name="ticker")

      private String ticker;

      @Column(name="indice")

      private String indice;

      @Column(name="pais")

      private String pais;

      @Column(name="rentabilidad")

      private Float rentabilidad;

     

      public Valor() {

             super();

      }

     

      public Valor(String nombre, String ticker, String indice, String pais

                    Float rentabilidad) {

             super();

             this.nombre = nombre;

             this.ticker = ticker;

             this.indice = indice;

             this.pais = pais;

             this.rentabilidad = rentabilidad;

      }

 

      public Valor(String nombre, String ticker, String indice, String pais

                    Float rentabilidad) {

             super();

             this.nombre = nombre;

             this.ticker = ticker;

             this.indice = indice;

             this.pais = pais;

             this.rentabilidad = rentabilidad;

      }

 

      public Valor(Long id, String nombre, String ticker, String indice, String pais

                    Float rentabilidad) {

             super();

             this.id = id;

             this.nombre = nombre;

             this.ticker = ticker;

             this.indice = indice;

             this.pais = pais;

             this.rentabilidad = rentabilidad;

      }

 

      public Long getId() {

             return id;

      }

      public void setId(Long id) {

             this.id = id;

      }

      public String getNombre() {

             return nombre;

      }

      public void setNombre(String nombre) {

             this.nombre = nombre;

      }

      public String getTicker() {

             return ticker;

      }

      public void setTicker(String ticker) {

             this.ticker = ticker;

      }

      public String getIndice() {

             return indice;

      }

      public void setIndice(String indice) {

             this.indice = indice;

      }

      public String getPais() {

             return pais;

      }

      public void setPais(String pais) {

             this.pais = pais;

      }

      public Float getRentabilidad() {

             return rentabilidad;

      }

      public void setRentabilidad(Float rentabilidad) {

             this.rentabilidad = rentabilidad;

      }

 

      @Override

      public String toString() {

             return "Valor [id=" + id + ", nombre=" + nombre + ", ticker=" + ticker +

                     ", indice=" + indice + ", pais=" + pais +  

                     ", rentabilidad=" + rentabilidad + "]";

      }

     

}

// **************************************************   

 

7º) Tenemos que crearnos el fichero Properties con los parámetros de configuración de la conexión con la Base de Datos MySql. Por defecto, el nombre de este fichero tendrá que ser hibernate.properties. En nuestro ejemplo, vamos a configurarlo de este modo.

 

# Propiedades Hibernate

hibernate.connection.driver_class = com.mysql.jdbc.Driver

hibernate.connection.url = jdbc:mysql://localhost:3306/universojava?useSSL=false&amp;serverTimezone=UTC

hibernate.connection.username = root

hibernate.connection.password = root

hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

hibernate.show_sql=true

hibernate.c3p0.min_size=5

hibernate.c3p0.max_size=20

hibernate.c3p0.timeout=1800

hibernate.c3p0.max_statements=50

#

 

8º) A continuación, tenemos que generar la clase que se encargará de crear el objeto SessionFactory a partir de la configuración que hayamos definido en hibernate.properties. Posteriormente, el SessionFactory nos permitirá crear las sesiones necesarias para acceder a la Base de Datos.

 

// **************************************************

package com.universo.annotated.config;

 

import java.util.Properties;

 

import org.hibernate.HibernateException;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;

 

import com.universo.annotated.modelo.Valor;

 

public class HibernateUtil {

 

      // Declaracion de SessionFactory

    private static final SessionFactory itemSessionFactory;

   

    // Propiedades de BBDD

    private static final String DRIVER_CLASS_BBDD = "com.mysql.jdbc.Driver";

    private static final String URL_SCHEMA_BBDD

         "jdbc:mysql://localhost:3306/universojava?serverTimezone=UTC";

    private static final String USERNAME_BBDD = "root";

    private static final String PASSWORD_BBDD = "root";

    private static final String DIALECT_BBDD = "org.hibernate.dialect.MySQLDialect";

   

    // static --> Inicializacion en el momento de la carga de la clase

    static {

             try {

                   // Creacion de las Propiedades requeridas

                   Properties hibernateProperties= new Properties();     

                  hibernateProperties.setProperty("hibernate.connection.driver_class",                                                         DRIVER_CLASS_BBDD);

                  hibernateProperties.setProperty("hibernate.connection.url",                                                                 URL_SCHEMA_BBDD);

                  hibernateProperties.setProperty("hibernate.connection.username",                                                             USERNAME_BBDD);

                  hibernateProperties.setProperty("hibernate.connection.password",                                                             PASSWORD_BBDD);

                   hibernateProperties.setProperty("hibernate.dialect", DIALECT_BBDD);

             

                   //  Creacion de Configuracion

                   Configuration config = new Configuration();

                  

                   // Provision de las Propiedades requeridas por Hibernate

                   config.setProperties(hibernateProperties);

                  

                   // Añadir la clases  que mapean tablas de BBDD

                   config.addAnnotatedClass(Valor.class);

                  

                   // Inicializar SessionFactory

                   itemSessionFactory = config.buildSessionFactory();

                  

             } catch (Throwable ex) {

                   throw new ExceptionInInitializerError(ex);

             }

    }

   

  /**

  * Obtencion de Sesion para cada transaccion sobre la BBDD

  */

  public static Session getSession() throws HibernateException {

             return itemSessionFactory.openSession();

      }

 

} 

// **************************************************

 

🚨 Hay que puntualizar que, si no se establece ningún set de Propiedades para el Configuration, los parámetros se recogerán por defecto del fichero hibernate.properties. Por contra, si procedemos a asignar Properties al Configuration, dichas propiedades tendrán prioridad sobre los valores indicados en el fichero hibernate.properties.

 

9º) Ahora procedemos a crearnos el repositorio donde se realizarán las diferentes operaciones de acceso a Base de Datos. En nuestro caso, nos crearemos una clase ValorRepo.java donde implementaremos un sencillo CRUD.


// **************************************************

package com.universo.annotated.repositorio;

 

import org.hibernate.Session;

 

import com.universo.annotated.config.HibernateUtil;

import com.universo.annotated.modelo.Valor;

 

public class ValorRepo {

 

    // Crear valor

    public void crear(Valor valor) {

   

       System.out.println("Crear valor: " + valor.toString());

    

        // abrir sesion

       Session session = HibernateUtil.getSession();

        session.beginTransaction();

    

        session.save(valor);

    

        // cerrar sesion

        session.getTransaction().commit();

        session.close();

       

    }

 

    // Obtener valor

    public void obtener(long id) {

       

          System.out.println("Obtener valor con Id: " + id);

       

          // abrir sesion

          Session session = HibernateUtil.getSession();

        

          Valor valor = session.get(Valor.class, id);

       

          System.out.println("Valor: " + valor.toString());

       

          // cerrar sesion

          session.close();

          

    }

 

    // Modificar valor

    public void modificar(Valor valor) {

     

       System.out.println("Actualizar valor: " + valor.toString());

     

       // abrir sesion

       Session session = HibernateUtil.getSession();

        session.beginTransaction();

    

        session.update(valor);

    

        // cerrar sesion

        session.getTransaction().commit();

        session.close();

       

    }

 

    // Eliminar valor

    public void eliminar(long id) {

      

        System.out.println("Eliminar valor con Id: " + id);

       

        Valor valor = new Valor();

        valor.setId(id);

    

        // abrir sesion

        Session session = HibernateUtil.getSession();

        session.beginTransaction();

    

        session.delete(valor);

       

        // cerrar sesion

        session.getTransaction().commit();

        session.close();

       

    }

   

}

// **************************************************


Creación de clase de prueba del proyecto

 

10º) Vamos ahora a crearnos una clase para poder realizar algunas pruebas con el repositorio que nos acabamos de crear. La idea es validar que funcionan correctamente todas las operaciones de acceso a nuestra tabla "valor" de MySql. 

Por tanto, nos creamos una clase main AppHibernate.java con la intención de obtener el contenido del Valor correspondiente al Id = 6.


// **************************************************

package com.universo.annotated.defecto;

 

import com.universo.annotated.config.HibernateUtil;

import com.universo.annotated.repositorio.ValorRepo;

 

public class AppHibernate {

 

      public static void main(String[] args) {

             // TODO Auto-generated method stub

 

          ValorRepo repo = new ValorRepo();

 

          // Identificadores

          long valorId1 = 6;

         

          // Crud

          repo.obtener(valorId1);


      }

     

} 

// **************************************************


11º) Una vez creadas todas las clases anteriores, ya estaríamos en disposición de ejecutar nuestra aplicación. La estructura de nuestro proyecto debería quedar del siguiente modo.


 

Probando nuestra Configuración de Hibernate

 

12º) Si ejecutamos AppHibernate.java, nuestra aplicación debería acceder a la tabla "valor" y recuperar el Valor con Id = 6 (Facebook). La salida de la ejecución es la siguiente.

 

ago 04, 2021 4:32:05 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator

INFO: HHH10001001: Connection properties: {user=root, password=****}

ago 04, 2021 4:32:05 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator

INFO: HHH10001003: Autocommit mode: false

ago 04, 2021 4:32:05 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>

INFO: HHH000115: Hibernate connection pool size: 20 (min=1)

ago 04, 2021 4:32:06 PM org.hibernate.dialect.Dialect <init>

INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect

ago 04, 2021 4:32:07 PM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService

INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]

Hibernate: select valor0_.id as id1_0_0_, valor0_.indice as indice2_0_0_, valor0_.nombre as nombre3_0_0_, valor0_.pais as pais4_0_0_, valor0_.rentabilidad as rentabil5_0_0_, valor0_.ticker as ticker6_0_0_ from valor valor0_ where valor0_.id=?

Valor: Valor [id=6, nombre=Facebook, ticker=FB, indice=Nasdaq-100, pais=EEUU, rentabilidad=41.41]

 

Tal y como se aprecia en la salida, el acceso a MySql ha recuperado el registro con id=6, que era justamente lo que esperábamos encontrar.

 

13º) Vamos a probar ahora el alta de registros. Para ello, en AppHibernate.java tendremos que incluir un código de este estilo. El objetivo es crear el registro correspondiente a la empresa "Berkshire".


// Valores

Valor valor1 = new Valor("Berkshire", "BRK.B", "Nasdaq-100", "EEUU", 42.14f);      

         

// Crud

repo.crear(valor1);

 

Si ejecutamos el código anterior, en la consola de Eclipse deberíamos obtener una salida del siguiente modo.

 

Crear valor: Valor [id=null, nombre=Berkshire, ticker=BRK.B, indice=Nasdaq-100, pais=EEUU, rentabilidad=42.14]

ago 04, 2021 4:36:04 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator

INFO: HHH10001001: Connection properties: {user=root, password=****}

ago 04, 2021 4:36:04 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator

INFO: HHH10001003: Autocommit mode: false

ago 04, 2021 4:36:04 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>

INFO: HHH000115: Hibernate connection pool size: 20 (min=1)

ago 04, 2021 4:36:05 PM org.hibernate.dialect.Dialect <init>

INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect

ago 04, 2021 4:36:05 PM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService

INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]

Hibernate: insert into valor (indice, nombre, pais, rentabilidad, ticker) values (?, ?, ?, ?, ?)

 

👉 Y, por supuesto, tras la ejecución del proceso el registro deberá haber quedado dado de alta en la Base de Datos MySql. 

 

14º) Toca probar la actualización del MySql. En nuestro ejemplo, tenemos que corregir el error y asociar la empresa "Berkshire" al índice "SP500". Para ello, en la clase AppHibernate.java incluimos el siguiente código. 


// Valores      

Valor valor2 = new Valor(7l, "Berkshire", "BRK.B", "SP-500", "EEUU", 42.14f);


// Crud

repo.modificar(valor2);


Si ejecutamos el código anterior, en la consola de nuestro Eclipse deberíamos obtener una salida del siguiente modo.

 

Actualizar valor: Valor [id=7, nombre=Berkshire, ticker=BRK.B, indice=SP-500, pais=EEUU, rentabilidad=42.14]

ago 04, 2021 4:40:51 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator

INFO: HHH10001001: Connection properties: {user=root, password=****}

ago 04, 2021 4:40:51 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator

INFO: HHH10001003: Autocommit mode: false

ago 04, 2021 4:40:51 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>

INFO: HHH000115: Hibernate connection pool size: 20 (min=1)

ago 04, 2021 4:40:52 PM org.hibernate.dialect.Dialect <init>

INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect

ago 04, 2021 4:40:53 PM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService

INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]

Hibernate: update valor set indice=?, nombre=?, pais=?, rentabilidad=?, ticker=? where id=? 


👉 Tras la ejecución del proceso, podremos comprobar que el registro ha quedado modificado en la Base de Datos MySql.


 

15º) Por último, vamos a probar la eliminación de registros de la Base de Datos. Para ello, procedemos a borrar uno de los valores existentes mediante la inclusión en AppHibernate.java del siguiente código.

 

// Identificadores

long valorId2 = 2;

 

// Crud

repo.eliminar(valorId2);


Si ejecutamos el código anterior, en la consola de nuestro Eclipse deberíamos obtener una salida del siguiente modo.

 

Eliminar valor con Id: 2

ago 04, 2021 4:43:59 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator

INFO: HHH10001001: Connection properties: {user=root, password=****}

ago 04, 2021 4:43:59 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator

INFO: HHH10001003: Autocommit mode: false

ago 04, 2021 4:43:59 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>

INFO: HHH000115: Hibernate connection pool size: 20 (min=1)

ago 04, 2021 4:44:00 PM org.hibernate.dialect.Dialect <init>

INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect

ago 04, 2021 4:44:00 PM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService

INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]

Hibernate: delete from valor where id=?

 

👉 Tras la ejecución del proceso, podremos comprobar que el registro ha quedado eliminado de la Base de Datos MySql.  


Con los pasos que acabamos de comentar ya deberíamos tener una idea más o menos clara de cuáles son las tareas que debemos realizar para elaborar un proyecto Hibernate usando la configuración mediante Properties y Annotated Class. Obviamente, la estructura del proyecto se puede complicar mucho más, pero aquí tenemos todo lo necesario para implementar un CRUD básico. Junto con la configuración XML que comentamos hace algunas semanas, ya tenemos dos alternativas para arrancar el framework Hibernate. Eso sí, tened en cuenta que la versión XML ya empieza a encontrarse, como se dice, "deprecated".


Pues nada, eso era todo lo que tenía que comentar en relación con la configuración Annotated Class de un proyecto Hibernate. Espero que lo comentado en el post sea suficiente para que podáis empezar a implementar vuestros propios proyectos. Ya sabéis que las dudas podéis dejármelas aquí abajo.

 

Saludos.


Comentarios

Entradas populares de este blog

Componentes y Ventanas de Java Swing

Creación de Webservice SOAP básico

Eliminar duplicados de una Lista en Java