You are on page 1of 41

Introduccin a hibernate

Diciembre 2008

Jos A. Garca jagarcia@siteframe.tk

Dos mundos distintos


Hoy en da, la prctica totalidad de los lenguajes de programacin que surgen son orientados a objetos y esta tecnologa se ha convertido en el estndar actual de programacin que, a su vez, est generando nuevos desarrollos muy prometedores para el futuro (como, por ejemplo, la programacin orientada a aspectos).

Dos mundos distintos


La programacin orientada a objetos intenta modelar estos objetos reales con estructuras de programa, llamadas objetos de software o, simplemente, objetos. Cada uno de estos objetos de software, est compuesto por una serie de caractersticas (llamadas atributos) y una serie de acciones (llamadas mtodos).

Si nuestros coches incluyen piezas tenemos una agregacin de objetos

Dos mundos distintos


El modelo relacional es muy diferente del modelo orientado a objetos. Por una parte, el modelo relacional slo se ocupa de la parte esttica de la aplicacin (de los datos) y no de la parte dinmica (los procesos). Hay otra gran diferencia entre ambos, la forma en la que el modelo relacional trata los datos es muy diferente a cmo lo hace el modelo orientado a objetos. Mientras en este ltimo, los datos son modelados en forma de objetos, en el modelo relacional son modelados como registros planos.

Incompatibilidades entre OO y MR
El problema aparece cuando intentamos traducir objetos a tablas relacionales.
Granularidad Subtipos Identidad Asociaciones direccionales

March 12, 2009

Problema de la Granularidad
Los objetos en OO son multidimensionales En SQL los tipos y las relaciones entre tablas son planas y hay un escaso soporte para tipos definidos por el usuario. Esto fuerza a los desarrolladores a usar estructuras menos flexibles en el modelo de objetos.

March 12, 2009

Problema de los Subtipos


Los objetos java soportan herencia (super & sub clases). Cada sub o super clase puede definir datos distintivos y funcionalidad diferente. Un objeto puede ser asociado con objetos de diferentes clases pero del mismo tipo (polimorfismo). SQL no soporta relaciones de herencia ni polimorfismo.

March 12, 2009

Problema de la Identidad
Comprobar si dos objetos son iguales Java define dos notaciones: Identidad de objetos [==] Equivalencia de valor [.equals()] Para SQL dos registros son el mismo si contienen la misma clave primaria. Dos o ms objetos pueden representar la misma fila (registro) en la BBDD.

March 12, 2009

Problema de las Asociaciones


Las asociaciones relacionan entidades. En Java una referencia a un objeto representa una asociacion. En SQL una asociacion esta representada por una foreign key. Las referencias a objetos son direccionales las FK no.

March 12, 2009

Diferencias en la navegacin
Los objetos son accedidos de forma totalmente diferente en Java y en SQL obj.getDetails().getFirstField() En SQL estos detalles se obtendrian a travs de uno o varios join.

March 12, 2009

10

El coste de estas diferencias


Requieren un esfuerzo y un tiempo considerable Alrededor 30-40% del esfuerzo se dedica a operaciones tediosas de SQL/JDBC

March 12, 2009

11

Object/relational Mapping (ORM)


La solucin es la misma que se dara en la vida real. Se debe encontrar un traductor que sepa traducir de cada idioma al otro. De esta forma, las dos personas se entendern sin necesidad de que uno hable el idioma del otro. En el mundo de la programacin este traductor no es ms que un componente de software (concretamente, una capa de programacin), al que se le dan los nombres de capa de persistencia, capa de datos, correspondencia O/R (OR mapping) o motor de persistencia. Nosotros veremos Hibernate ORM.

Object/relational Mapping (ORM)


Para rescatarnos de tanta tediosidad aparecen los ORM. Un ORM es una herramienta que permite automatizar la mayor parte del acceso no critico a la BBDD, persistiendo los objetos de forma automtica y transparente.

March 12, 2009

13

Tipos de ORM

1. Puramente relacional
Generan el modelo de objetos equivalente al modelo relacional Desaprovechan las ventajas OO, y son dificilmente portables. Utilizan SQL/JDBC para crear soluciones de mapeo a medida Esta solucin continua siendo muy popular Son capaces de generar el cdigo relacional en tiempo de ejecucin para los casos mas simples Soportan modelado de caracterscas sofisticadas como: composicion, herencia, polimorfismo & persistencia.

2. Mapeo ligero 3. Mapeo bsico 4. Mapeo avanzado

Hibernate es un ORM de tipo 4.


March 12, 2009 14

Pero que nos aporta realmente Hibernate sobre JDBC?


PROGRAMACIN MAS LIMPIA. Con jdbc el cdigo de bbdd se entremezcla con el resto. Hibernate nos provee una capa de abstraccin con la bbdd y una capa de persistencia perfectamente aisladas. INDEPENDENCIA DE LA BBDD PERO TAMBIEN DE SU DIALECTO CONTROL DE TRANSACCIONES mediante JTA. CONVERSION Y VALIDACION de tipos automtica.
March 12, 2009 15

Pero que nos aporta realmente Hibernate sobre JDBC?


INTEGRACION PERFECTA CON XDOCLET y anotaciones de JDK 5. Mapeo avanzado de asociaciones.

March 12, 2009

16

Ventajas de usar ORM


Esta solucin goza de las mejores ventajas de los dos modelos:
Por una parte, podemos programar con orientacin a objetos, aprovechando las ventajas de flexibilidad, mantenimiento y reusabilidad. Por otra parte, podemos usar una base de datos relacional, aprovechndonos de su madurez y su estandarizacin as como de las herramientas relacionales que hay para ella.

Se calcula que un motor de persistencia puede reducir el cdigo de una aplicacin en un 40%, hacindola menos costosa de desarrollar. Adems, el cdigo que se obtiene programando de esta manera es ms limpio y sencillo y, por lo tanto, ms fcil de mantener y ms robusto.

Primera clase con hibernate

Primera clase con hibernate

La estructura de Bean es muy importante para hibernate ya que la capa de persistencia autoinstanciar las clases y no podra hacerlo si no proveemos un constructor vacio. Hibernate reconoce los mtodos standart SET, GET, IS..

El archivo de mapeo
Hibernate necesita saber cmo cargar y almacenar objetos de la clase persistente. Aqu es donde entra en juego el archivo de mapeo. Un archivo de mapeo es un archivo XML que cumple con el DTD de los archivos de mapeo de hibernate. Este DTD es complicado por lo que lo iremos viendo poco a poco.

El archivo de mapeo
Para nuestro ejemplo el fichero de mapeo podra ser:

La etiqueta CLASS es la mas importante porque define la tabla de la bd donde se persisten los objetos La etiqueta ID define el mapeo del identificador nico a la clave primaria de la tabla. La etiqueta GENERATOR indica una estrategia de generacin automtica. En este caso de tipo nativo.

El archivo de mapeo
Para nuestro ejemplo el fichero de mapeo podra ser:

La etiqueta PROPERTY declara una propiedad persistente. POR DEFECTO TODAS LAS PROPIEDADES DE LA CLASE SON NO PERSISTENTES. El atributo name declara el nombre de la propiedad java. Hibernate usar ese nombre para acceder a Los mtodos GET/SET correspondientes.

El archivo de mapeo
Para nuestro ejemplo el fichero de mapeo podra ser:

Por qu el mapeo de la propiedad date incluye el atributo column pero el de title no? Por qu el mapeo de title no incluye type? Hibernate no puede decidir automaticamente si el tipo de la columna que proviene de un atributo Java.util.Date ser Date Time Timestamp.

Configurar el entorno
Para la configuracin de Hibernate podemos usar un simple archivo hibernate.properties, un archivo hibernate.cfg.xml algo ms complicado, o incluso una configuracin totalmente en tiempo de ejecucin. Probablemente la solucin mas versatil sea el fichero xml. Para nuestro ejemplo el fichero cfg.xml podra ser:

Configurar el entorno

Lo primero que hay que darse cuenta es que este fichero tiene su propia DTD que tenemos que seguir. Configuramos la SessionFactory una fabrica global responsable de una base de datos en particular.

Configurar el entorno

La propiedad hibernate.dialect especifica la variante de SQL que hibernate generar para hablar con la BD. Al contrario que JDBC hibernate nos permite adaptarnos al dialecto hablado por la BD.

Configurar el entorno

La propiedad hibernate.current_session_context_class es muy importante porque define el comportamiento de las sesiones. En este caso la unidad de trabajo de hibernate queda ligada al thread de java que se este ejecutando en el momento de crearla. Veremos esto mas adelante.

Configurar el entorno

Por ltimo declaramos los ficheros que contendrn los mapeos de los objetos en la BD.

HibernateUtil.java
Llegados a este punto Hibernate es capaz de conectar con nuestra BBDD, manejar la conexin independientemente de que esta se obtenga a travs de JDBC o de otros mecanismos como JNDI, y escribir-leer objetos en ella. Lo nico que necesitamos es una clase que nos permita comunicarnos con hibernate para solicitarle operaciones. Esta clase es HibernateUtil.java

Lo que nos va a importar de hibernateUtil.java es que nos provee de una clase singleton capaz de crear un objeto SessionFactory de forma unica, mantenerlo de forma global y devolverlo de forma facil.

HibernateUtil.java
Una implementacin bsica de HibernateUtil suele estar incluida en todos los entornos de desarrollo y en nuestro caso podra ser:

Comenzando a usar Hibernate


Ya podemos usar Hibernate, nuestra primera prueba ser salvar un evento. Simplemente hacemos:

Comenzando a usar Hibernate

Lo primero que hacemos es obtener la unidad de trabajo actual (CurrentSession) a travs de HibernateUtil. Hemos asignado cada unidad de trabajo a un thread. Una sesin comienza cuando se la necesita por primera vez, entonces queda ligada al thread actual. Si volvemos a llamar a getCurrentSession obtenemos la misma unidad de trabajo. Una vez que la transaccin termina Hibernate desliga la sesin y la cierra automaticamente.

Comenzando a usar Hibernate

Una transaccin en la BD siempre se inicia invocando al mtodo beginTransaction() del objeto sesin y terminar bien en una confirmacin, bien en una orden deshacer.

Comenzando a usar Hibernate


Igual de fcil seria la recuperacin de datos desde tablas (generacin de objetos):

Lo que hicimos aqu, es usar el lenguaje de consultas de Hibernate (HQL, por sus siglas en ingls) para cargar todos los objetos Event que existen en la base de datos. Hibernate generar el cdigo SQL que haga falta, lo enviar la base de datos, y poblar los objetos Event con los datos que sean devueltos. Se pueden crear consultas SQL mucho ms complejas con HQL, por supuesto. Pero es importante que esto no es SQL sino HSQL, que veremos en detalle mas adelante.

Ejercicio inicial
Crear un proyecto base en NetBeans integrando Hibernate.

hacer en clase

Otro Ejemplo
public class Message { private Long id; private String text; private Message nextMessage; private Message() {} public Message(String text) { this.text = text; } public Long getId() { return id; } private void setId(Long id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public Message getNextMessage() { return nextMessage; } public void setNextMessage(Message nextMessage) { this.nextMessage = nextMessage; } }

36

Otro Ejemplo
La clase mensaje puede ser usada como cualquier otra clase
Message message = new Message("Hello World"); System.out.println( message.getText() );

Usamos hibernate para persistir los datos a la BBDD


Session session = getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); Message message = new Message("Hello World"); session.save(message); tx.commit(); session.close();

37

Otro Ejemplo
El Cdigo de traduce a
insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID) values (1, 'Hello World', null)

38

Otro Ejemplo Podemos recrear el Objeto as


Session newSession = getSessionFactory().openSession(); Transaction newTransaction = newSession.beginTransaction(); List messages = newSession.find("from Message as m order by m.text asc"); System.out.println( messages.size() + " message(s) found:" ); for ( Iterator iter = messages.iterator(); iter.hasNext(); ) { Message message = (Message) iter.next(); System.out.println( message.getText() ); } newTransaction.commit(); newSession.close();
39

Otro Ejemplo
Que se traducira a:
select m.MESSAGE_ID, m.MESSAGE_TEXT,m.NEXT_MESSAGE_ID from MESSAGES m order by m.MESSAGE_TEXT asc

40

Otro Ejemplo
Podemos Actualizar un mensaje haciendo:
Session session = getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); // 1 is the generated id of the first message Message message = (Message) session.load( Message.class, new Long(1) ); message.setText("Greetings Earthling"); Message nextMessage = new Message("Take me to your leader (please)"); message.setNextMessage( nextMessage ); tx.commit(); session.close();

41