martes, 22 de agosto de 2017

Tutorial: comunicación entre Java y una base de datos H2 (con ejemplos): Parte 2 - Hibernate con XML

El tiempo pasaba y JDBC, con lo simple que era, tenía sus desventajas:

- El cambio de la BD? De Oracle a SQL Server ?


Venga - a parar el servidor, recompilar todo el proyecto y reiniciar el servidor. A un banco de parar su servidor de la producción por, digamos, una media hora, puede ser un problema....

- Fiabilidad

Si haces un pequeño programa para tu universidad o una pequeña empresa - no lo vas a notar. Pero que pasa, si tu aplicacion Java va ser ejecutada por miles de usuarios cada segundo? Imagina que 2 usuarios quieren a la vez actualizar la misma línea de BD, quien gana?

Por este motivo varios chavales han empezado a crear unas herramientas que se llamaban ORM (Object-Relational Mapping), donde las tablas y las relaciones entre las tablas en la BD están "mapeadas" en el código Java a traverso de los ficheros mapping XML (y mas tarde con el código Java usando las anotaciones).  Al mismo tiempo la manera, en que una aplicación Java guarda los datos en una BD ha tambien evolucionado y así apareció la capa de Persistance, donde los datos primero estaban guardados en los objetos simples de Java (POJO) que tenían los setters y getters y luego una sesión les guardaba en la base de datos a traverso de una transacción.

Los primeros eran los de JBoss que han creado Hibernate en 2001. En verdad hay un montón de frameworks ORM - IBATIS, EclipseLink y no solo en Java, pero tb en C#, PHP, etc. Pero Hibernate sigue siendo una de mas simples y mas populares.

Hoy vamos modificar nuestro proyecto que hemos creado un la parte 1 y en vez de utilizar la conexión a traverso de un driver JDBC, utilizamos Hibernate. Voy pegar otra vez la esquema de la BD:


Aquí en vez de abrir y cerrar la conexión manualmente, utilizamos una sesión Hibernate que actualiza las tablas a traverso de un mapping XML. El mapping XML refleja le estructura de una tabla SQL en un file XML.





Un ejemplo del mapping XML para la tabla Address:

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>
    <class name="entity.Address" table="ADDRESS">
        <id name="id" type="java.lang.Long">
            <column name="ID" />
            <generator class="identity" />
        </id>
        <property name="country" type="string">
            <column name="COUNTRY" length="255" not-null="true" />
        </property>
        <property name="city" type="string">
            <column name="CITY" length="255" not-null="true" />
        </property>
        <property name="street" type="string">
            <column name="STREET" length="255" not-null="true" />
        </property>
        <property name="postCode" type="string">
            <column name="POST_CODE" length="10" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

Como podéis ver, este file consiste de la propriedades que corresponden a las columnas de la tabla (y con características de cada columna - string, longitud, not-null, etc).

Hibernate consiste de estos files de mapping, un file de configuración hibernate.cfg (donde metemos los parámetros de la conexión de nuestra BD) y una clase que nos devuelve la sesión Hibernate para abrirla y cerrarla y que llamamos HibernateUtil.
Un ejemplo del file de configuración hibernate.cfg :

<hibernate-configuration>
<session-factory>
    <property name="hibernate.dialect">
        org.hibernate.dialect.H2Dialect
    </property>
    <property name="hibernate.connection.driver_class">
        org.h2.Driver
    </property>

    <!-- Assume test is the database name -->    <property name="hibernate.connection.url">
        jdbc:h2:~/test
    </property>
    <property name="hibernate.connection.username">ss</property>
    <property name="hibernate.connection.password"></property>
    <property name="show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">create</property>

    <!-- List of XML mapping files -->    <mapping resource="mapping/Address.hbm.xml"/>
    <mapping resource="mapping/Employee.hbm.xml"/>
    <mapping resource="mapping/Project.hbm.xml"/>

</session-factory>
</hibernate-configuration>

Un ejemplo de HibernateUtil :

public class HibernateUtil {

    //from hibernate cfg file    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            return new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void shutdown() {
        getSessionFactory().close();
    }

}

Esta clase me parece horrible de punto de vista de la programación orientada a los objetos y me hace daño solo de verla. En vez de hacer una cosa programáticamente correcta como session = new Session() y luego algo como session.open(), va en el objeto de la configuración, lo configura y de ahí, de tan lejos saca alguna factory que luego nos sirve para abrir la sesión! Mas lejos no puede ser.
Luego se abre la sesión, se inicia la transacción y se crean los objetos, se guardan y la transacción se cierra:

Session session = HibernateUtil.getSessionFactory().openSession();

session.beginTransaction();

Address address = new Address();
address.setCountry("DC");
address.setCity("Gotham City");
address.setStreet("Arkham street 1");
address.setPostCode("0987");

Employee employee = new Employee();
employee.setFirstName("James");
employee.setLastName("Gordon");

Calendar calendar = Calendar.getInstance();
calendar.set(1939, Calendar.MAY, 1);

employee.setBirthday(new Date(calendar.getTime().getTime()));
employee.setAddress(address);

Project project = new Project();
project.setTitle("5678");

Set<Project> projects = new HashSet<Project>();
projects.add(project);
employee.setProjects(projects);

session.save(address);
session.save(employee);
session.save(project);

session.getTransaction().commit();
HibernateUtil.shutdown();

Aquí creamos un empleador con su dirección, etc, le asignamos un proyecto y todo eso guardamos en nuestra BD.

El codigo puedes encontrar aqui: https://github.com/cyberglad/TutorialHibernateXML

No hay comentarios:

Publicar un comentario