jueves, 26 de noviembre de 2009

Hibernate Versioning - Consideraciones

Escenario:
_ Estrategia
session-per-request para manejo de sesiones.
_ Objetos detached manipulados en casos de negocio arbitrariamente largos.

Objetivo
:
_ Control de versiones automático por parte de Hibernate.

Caso
:
Considerar como ejemplo una clase Cliente, que necesita ser controlada para sincronización.
Dada la estrategia de uso de sesiones, es necesario utilizar un campo adicional en la tabla cliente para ingresar un número de versión.
_ Agregar un campo
int a la tabla, y agregar el atributo a la clase Cliente.

Configuración del mapping xml:
_ En Cliente.hbm.xml agregar el mapping para version, luego del tag <id>:
<version name="version" column="version" />

El comportamiento por defecto de Hibernate es realizar control de versiones a través de un campo en la tabla, pero de todas maneras se puede especificar, en el tag <class>:
optimistic-lock="version"

Manejar los errores de versión desde la aplicación
Cuando se intenta asociar una instancia de la clase Cliente a una Session nueva, por ejemplo a través de un update(), Hibernate lanzará una StaleObjectStateException.
El código para manejarlo puede ser el siguiente:

protected boolean update(PersistentObject objeto){
___Transaction
tx = getHibernateSession().beginTransaction();
___try {
______getHibernateSession().update(objeto);
______tx.commit(); // Aqui se produce la excepción
______closeSession();
______return true;
___}
___catch(StaleObjectStateException e) {
______tx.rollback();
______closeSession();
______return false;
___}
}

En una capa superior de la aplicación, se puede utilizar el resultado de esta función y algunos chequeos para saber si la excepción se produjo porque la instancia fue modificada o eliminada con anterioridad:

...
boolean valid = update(cliente);
if (valid) {
___// Update OK
___// <Código si update exitoso>
}
else{ // No se pudo actualizar el elemento
___// Verifico si fue modificado o eliminado
___// Intenta cargar el cliente de nuevo
___Cliente clienteRel = sess.load(Cliente.class, cliente.getIdCliente());
___if (clienteRel == null){ // El cliente fue borrado antes
______err_mesg = "El cliente fue borrado por otra aplicacion";
___}
___else{ // El cliente fue modificado antes
______err_mesg = "El cliente fue modificado por otra aplicacion";
___}
}
...


Aquí lo que obtenemos es la diferenciación de las distintas situaciones, y un mensaje de error apropiado para cada una.

No hay comentarios:

Publicar un comentario

 
 
Copyright © Slim code
Blogger Theme by BloggerThemes Design by Diovo.com