Mostrando entradas con la etiqueta Hibernate. Mostrar todas las entradas
Mostrando entradas con la etiqueta Hibernate. Mostrar todas las entradas

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.

miércoles, 14 de octubre de 2009

Manejo de versiones o 'versioning' con Hibernate

El manejo automático de versiones es una técnica simple para asegurar la integridad de datos.
Rápidamente podemos pensar en un ejemplo en donde tenemos 2 clientes A y B que cargan el mismo registro R. Luego de un tiempo A hace 'commit' de R con los datos cambiados, y después B hace lo mismo, cambiando los datos de R, pero no desde el estado de R luego del 'commit' de A.

Lo que hace el manejo automático de versiones es mantener un campo para versionar el registro. En el ejemplo anterior, A y B obtienen el registro R con una versión V. Luego del 'commit' de A la versión se cambia, y de esta forma cuando B intenta hacer lo mismo, las versiones son distintas y el chequeo de esta versión falla.

En Hibernate podemos declarar el campo de versión y se recomienda que sea del tipo int o long.
Aquí vemos un ejemplo en donde asumimos que el atributo se llama 'version' y lo queremos mapear a la columna 'version' en la base de datos:

<version name="version" column="version"/>

En general con Hibernate surgen dudas sobre cómo la aplicación se da cuenta de que un objeto ha cambiado en la base de datos.

El funcionamiento es el siguiente: Al usar Hibernate se deberia llamar a saveOrUpdate() o update() cuando se quiere actualizar un dato cambiado. Estos métodos lo que hacen es realizar una consulta del estilo:
UPDATE Persona SET nombre='juan', VERSION=2
WHERE ID=123 AND VERSION=1

Luego, Hibernate chequea la cantidad de filas afectadas en el resultado de JDBC, y lanza una excepción del tipo StaleObjectStateException si ninguna fila fue actualizada. De esta forma, podemos atrapar dicha excepción y darnos cuenta de que hubo un conflcto.
Algo importante a notar es que cada actualización incrementa el número de versión en uno y chequea que no haya sido cambiado desde que fue leído.
 
 
Copyright © Slim code
Blogger Theme by BloggerThemes Design by Diovo.com