Curso de Hibernate | Configuración por anotaciones

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.

Crearemos un proyecto con Maven siguiendo, utilizando este pom.xml.

Creamos el fichero hibernate.cfg.xml en la carpeta src/main/resources y le pegamos el siguiente código:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="hibernate.connection.isolation">2</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.connection.pool_size">10</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3307/siniestros?createDatabaseIfNotExist=true&amp;useSSL=false&amp;serverTimezone=UTC</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.current_session_context_class">managed</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hbm2ddl.auto">update</property>
    </session-factory>
</hibernate-configuration>

DDL automático

  • update → cada vez que arranquemos el servidor, se comprobará si hay cambios en las entidades de hibernate y si es así, se actualizará la base de datos en función de dichos cambios (en caso de que sea posible)
  • create → recrea la base de datos al arrancar, borrando lo que había
  • validate → comprueba que lo que tengo en la aplicación corresponde a lo que hay en la base de datos y si no es así, lanza un error

Si no pones el property, no se ejecuta ninguna acción.

hibernate.cfg.xml:
<property name="hbm2ddl.auto">create</property>

Creamos el fichero HibernateUtil.java para establecer la conexión

public class HibernateUtil {
	private static StandardServiceRegistry registry;
	private static SessionFactory sessionFactory;

	public static SessionFactory getSessionFactory() {
		if (sessionFactory == null) {
			try {
				registry = new StandardServiceRegistryBuilder().configure().build();
				MetadataSources sources = new MetadataSources(registry);
				sources.addAnnotatedClass(Libro.class);
				sources.addAnnotatedClass(Autor.class);
				Metadata metadata = sources.getMetadataBuilder().build();
				sessionFactory = metadata.getSessionFactoryBuilder().build();
			} catch (Exception e) {
				e.printStackTrace();
				if (registry != null) {
					StandardServiceRegistryBuilder.destroy(registry);
				}
			}
		}
		return sessionFactory;
	}
}

Las entities

@Entity
// Anotación opcional, permite especificar el nombre de la tabla vinculada a esta entidad en la base de datos
// @Table(name = "autorcillo")  
public class Autor {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)//Para generar números autoincrementados
	private int id;
	
	//Anotación opcional, permite easpecificar el nombre d ela tabla en la base de datos, los caracteres que tendrá y si acepta valores nulos
	//@Column (name = "nombrecillo", length = 100, nullable = true)
	private String nombre;
	
	// mappedBy especifica el atributo de la entidad vinculada con el que estamos estableciendo esta relacion.
	//Si no lo ponemos se gererará una tabla auxiliar.
	// CascadeType.ALL: Los datos se borrarán y se salvarán en cascada
	// orphanRemoval: si borro en cascada y queda algún registro hijo sin padre, cárgatelos también
	// eager = carga ansiosa 
	@OneToMany (mappedBy = "autor", cascade = {CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.EAGER) 
        // Cuando queremos consultar entidades con entidades relacionadas a través de peticiones http, esta anotación suele ser necesaria para que las entidades no se embuclen
        @JsonManagedReference
	private List<Libro> libros;

	// Los getters y setters
}
@Entity
public class Libro {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY) // Para generar números autoincrementados
	private int id;
	private String titulo;
	private int precio;
        @JsonBackReference
	@ManyToOne
	// Anotación opcional, permite especificar el nombre de la join column
	// @JoinColumn (name = "autor_id", nullable = false)
	private Autor autor;

	// ... los getters y setters
}

Generación de getters y setters con Lombok

Podemos getionar la generación automática de getters y setters en nuestras entidades utilizando las anotaciones de Lombok.

Pasos en su implementación

1. Debemos tener incluída la dependencia correspondiente en nuestro pom.xml:

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.30</version>
	<scope>provided</scope>
 </dependency>	

2.

En eclipse:

Debemos tener vinculado Lombok a nuestro editor de código. Para ello descargamos y ejecutamos el jar de Lombok. Durante la ejecución, se nos pedirá que indiquemos la ruta en la que tenemos instalado nuestro editor. Si todo esta correcto, tras la instalación, aparecerá un jar de lombok en la carpeta de nuestro editor. Reiniciamos el editor.

En Intellij:

Es posible que haya que hacer un rebuild del pom.xml (botón derecho sobre el pom.xml → Maven → Reload Project). Saldrá un popup invitandonos a instalar el plugin de Lombok.

3. Añadimos las siguientes anotaciones a la entidad. Esto genera automáticamente getters y setters para todas las propiedades.

@Getter @Setter
@Entity
public class Libro {

3. Ejecutamos el jar correspondiente a lombok que se habrá instalado a través de maven.

Curso de Hibernate | Configuración por anotaciones 1

4. En un momento de instalación se nos pregunta por la ubicación de nuestra instalación de Eclipse. Si la herramienta no lo detectase, deberemos especificar la ubicación manualmente.

5. A partir de ahora, podremos usar las anotaciones @Getter y @Setter para generar los getters y setters.

Probando la configuración con una transacción

Conjunto de operaciones contra la base de datos que se realizan de forma atómica (o todas o ninguna).

¿Cuando nos interesa crear una transacción? Cuando modificamos la base de datos (y por tanto deseamos poder hacer rollback()). Para una consulta no es necesario. Crear una transacción consume recursos.

  • Un objeto Session Hibernate representa una única unidad-de-trabajo y es abierta por un ejemplar de SessionFactorySe deben cerrar las sesiones cuando se haya completado todo el trabajo de una transación.
  • En caso de fallo, lo que hay dentro del beginTransaction y el commit no se ejecuta y se salta a un catch.
  • Siempre es más rápido hacer dos operaciones en una sola transacción que dos operaciones en dos transacciones.
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
Autor a = new Autor();
a.setNombre("Juan");
		
session.save(a);
transaction.commit();
session.close();

setTimeout()

sesion.beginTransaction().setTimeout(400);
  • Si pasados 400 milisegundos la base de datos no devuelve nada, se arrojará una UnCaught Eception (una excepción para la que no es estrictamente neceario tener un try catch; al contrario que las Caught Exception).
  • Este timeout se puede gestionar a nivel de aplicación o a nivel de base de datos.

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.