4.1 Introducción a las transacciones en Hibernate

A todo lo anterior, me gustaría agregar información sobre transacciones. Como ya sabes, una transacción es un conjunto de acciones que se deben realizar únicamente en conjunto . Si alguna acción falló o se ejecutó con un error, todas las demás acciones deben cancelarse.

Hibernate puede trabajar con dos tipos de transacciones:

  • JDBC
  • JTA

Una transacción JDBC es en realidad una transacción de base de datos. Está ligado al trabajo con la base de datos, a la conexión JDBC. Y se asegura de que las acciones al trabajar con la base de datos se realicen como deben: o todo o nada.

JTA: la transacción es una transacción a nivel de aplicación. No está vinculado a ninguna base de datos. Su tarea es asegurar que se realicen ciertas acciones: o todo o nada.

Por ejemplo, puede escribir datos en varias bases de datos diferentes dentro de una sola transacción JTA. Luego, si ocurre un error, la transacción JTA tendrá que revertir los cambios en todas las bases de datos. Incluso aquellos que se ejecutaron con éxito en términos de una base de datos en particular.

4.2 Interfaz de transacciones de Hibernate

En la biblioteca de Hibernate, una transacción está representada por la interfaz Transaction, que puede tener diferentes implementaciones. Por ejemplo, cuando se trabaja con Spring, Spring proporciona su propio mecanismo de transacción JTA.

Los métodos de esta interfaz son:

# Método Descripción
1 comenzar() Comienza una nueva transacción
2 comprometerse() Finaliza la transacción, empuja/confirma todos los cambios
3 Retroceder() Revierte la transacción actual
4 setTimeout(int segundos) Establece el tiempo máximo de ejecución de la transacción
5 está activo() Comprueba si una transacción está activa o no
6 wasRolledBack() Comprueba si la transacción se revirtió normalmente
7 fue cometido() Comprueba si la transacción se ha comprometido normalmente
8 registrarseSincronización() Registra una devolución de llamada para controlar la transacción.

¡Importante! Crear un objeto de transacción e iniciar una transacción son dos cosas diferentes. Aquí puede dibujar una analogía con la clase Thread. Cuando crea un objeto Thread(), la JVM aún no inicia un nuevo hilo. Para iniciarlo, debe llamar al método start() en el objeto Thread. Es lo mismo con una transacción: necesita llamar al método begin().

Un ejemplo de cómo se manejan normalmente las transacciones en Hibernate:


Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
try {
    transaction.begin();
    Long count = session.createQuery("select count(*) from Employee", Long.class).uniqueResult();
    transaction.commit();
}
catch (Exception e) {
	if (transaction.getStatus() == ACTIVE || transaction.getStatus() == MARKED_ROLLBACK) {
    transaction.rollback();
    }
}
finally {
	session.close();
	sessionFactory.close();
}

Aquí vemos tres cosas:

En primer lugar, todo el trabajo con la base de datos se envuelve en una transacción mediante métodos de llamada begin()y commit()se deben realizar todas las acciones entre llamadas a estos dos métodos: o todos juntos o nada.

En segundo lugar, si se produce algún error, intentamos revertir la transacción: llame al rollback(). Esto quiere decir que TransactionManger primero debe registrar todas las acciones que hubo entre begin()y commit(), y luego devolver todo como estaba si lo invocamos rollback().

Y, por cierto, no es un hecho que no habrá ningún error al llamar al método de reversión. Los errores siempre suceden. Solo necesita aceptar este hecho y estar preparado para ello.

4.3 Administrador de transacciones

Desde la perspectiva de la gestión de transacciones, Hibernate es solo un contenedor de objetos ligero para JDBC. Hibernate en sí mismo no tiene funciones de procesamiento de transacciones. Hibernate Transaction es en realidad un contenedor para la transacción JDBC subyacente (o contenedor de transacciones JTA). JDBCTransaction es el predeterminado. Ejemplo del archivo de configuración de Hiberante:


hibernate.transaction.factory_class  org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.factory_class  org.hibernate.transaction.JDBCTransactionFactory

Echemos otro vistazo a nuestro código usando transacciones:


Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
//here is your code for working with the base
session.flush();
transaction.commit();
session.close();

Ahora veamos el código de la clase JDBCTransaction:


public class JDBCTransaction implements Transaction {
 
    public void begin() throws HibernateException {
    	...
    	if (toggleAutoCommit) jdbcContext.connection().setAutoCommit(false);
    	...
    }
}

Este es el método para iniciar una transacción. Luego mira el método de envío:


public void commit() throws HibernateException {
    ...
    jdbcContext.connection().commit();
    ...
    jdbcContext.connection().setAutoCommit( true );
    ...
}

Ahora sustituyamos este código en el código de ejemplo de Hibernate:

Hibernar Código JDBC simple

Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
//here is your code for working with the database
session.flush();
transaction.commit();
session.close();

Connection conn = jdbcContext.connection();
conn.setAutoCommit(false);
 
//here is your database code
conn.commit ()
conn.setAutoCommit(true);
conn.close();

Entonces, las transacciones nativas de Hibernate son solo llamadas JDBC nativas a la base de datos. Nada más y nada menos. Pero las transacciones JTA son más interesantes. Pero más sobre eso en otro momento.