Transacciones en Java - JTA - Java Transaction API

Una transacción es una operación en la que se realizan una serie de operaciones de forma completa, o no se realiza ninguna.
Por ejemplo, si tenemos que hacer una transferencia de una cuenta a otra en un banco, las dos operaciones forman un conjunto. No sería lógico que quitásemos efectivo de una cuenta y, por alguna razón, no pudiéramos ingresar el dinero en la cuenta de destino, o se realizan las dos operaciones o ninguna.
Una vez iniciada una transacción, ningún cambio queda reflejado hasta que no se confirmen las operaciones ("commit"), o se anulen las mismas ("rollback").
El API de Java para manipular transacciones se conoce como JTA (Java Transaction Api).

Existen tres conceptos de transacciones que son importantes para el desarrollo de aplicaciones Java EE.
  • Atomicidad. Las operaciones son un conjunto completo, o todas se realizan bien o si falla alguna, fallan todas a la vez.
  • Locking and Isolation. Dicho término implica que solamente una transacción puede actualizar un dato al mismo tiempo.
  • Modelo. Cuantas transacciones pueden estar activas en un mismo thread (hilo) en particular en un momento dato.
Existen varios modelos de transacciones:
  • Anidado (Nested). Una transacción consta de varias sus transacciones que corren en paralelo todas juntas.
  • Encadenado (Chained). Una transacción consta de varias subtransacciones que corren en secuencia.
  • Plano (Flat): Una transacción no puede contener subtransacciones. La plataforma Java EE solamente soporta el modelo plano.
El servicio de transacciones distribuidas de la Plataforma J2EE involucra cinco participantes diferentes:
  • Transaction Manager (TM): Es el encargado de proveer los servicios para demarcación de transacciones, manejo de recursos transaccionales, sincronización y propagación de contexto transaccional.
  • Application Server: Implementa los servicios necesarios para proveer un entorno de ejecución para las aplicaciones. Entre estos servicios está el manejo del estado transaccional.
  • Resource Manager (RM): Ofrece a las aplicaciones acceso a recursos. Este acceso se ofrece a través de Resource Adapters. Este participa de transacciones implementado una interfaz para el manejo de recursos transaccionales, que controla la asociación a una transacción, la finalización de una transacción y la recuperación de una transacción.
  • Aplicación basada en componentes transaccionales: Esta aplicación se ejecuta sobre un servidor de aplicaciones, el cual le ofrece, entre otros servicios, control de transacciones, como por ejemplo, una aplicación basada en Enterprise Java Bean.
  • Communication Resource Manager: Encargado de la propagación del contexto transaccional permitiendo acceder a recursos transaccionales ubicados en otros dominios.
Existen dos formas de representar las transacciones sobre las cuales el sistema está sujeto:
  • Mediante programación. Existe un bean que controla la transacción. Esta forma se llama Bean-Managed Transaction (BMT).
  • De forma declarativa. El desarrollador solamente debe establecer de forma declarativa como quiere que el contenedor maneje las transacciones. Esta forma lleva el nombre de Container-Managed Transactions (CMT).
En la primera especificación de EJB se propusieron dos modelos de componentes, conocidos como Entity Bean y Session Bean. La especificación 2.0 introduce un nuevo modelo de componente llamado Message Driven Bean.  

Atributos de Transacciones

Los atributos de las transacciones se especifican mediante anotaciones u opcionalmente, en un deployment descriptor. Las anotaciones de los atributos son las siguientes:
Required  @TransactionAttribute(REQUIRED) Si un cliente está corriendo dentro una transacción e
invoca un método de un bean, el método se ejecuta dentro de la
misma transacción. 
RequiresNew  @TransactionAttribute(REQUIRES_NEW) 
Si un cliente está corriendo dentro de una transacción e invoca un
método, la transacción del cliente se suspende, se inicia una
nueva, la cual se termina al finalizar el método y se reinicia la
transacción del cliente.  
Mandatory  @TransactionAttribute(MANDATORY) Mandatory  @TransactionAttribute(MANDATORY) 
Si el cliente está corriendo dentro una transacción e invoca un método
de un bean, el método se ejecuta dentro de la misma transacción. 
NotSupported  @TransactionAttribute(NOT_SUPPORTED).
Si el cliente está corriendo dentro de una transacción e invoca un método, la transacción del cliente se suspende, cuando termina el método, la transacción del cliente se reanuda.
Si el cliente no está asociado a una transacción, el contenedor no inicia una nueva.
Supports  @TransactionAttribute(SUPPORTS) 
Si el cliente está corriendo dentro una transacción e invoca un método de un bean, el método se ejecuta dentro de la misma transacción.
Si el cliente no está asociado con una transacción, el contenedor no inicia una nueva.
Never  @TransactionAttribute(NEVER) 
 
Ejemplo de código de una transacción:
 
@TransactionAttribute(NOT_SUPPORTED)
@Stateful
public class BeanTransacciones implements Transaction {
...
@TransactionAttribute(REQUIRES_NEW) @TransactionAttribute(REQUIRES_NEW)
public void PrimerMetodo() {...}
@TransactionAttribute(REQUIRED)
public void SegundoMetodo() {...}
public void TercerMetodo() {...}
public void CuartoMetodo() {...}
}
 
Para delimitar las transacciones JTA, se utilizan los siguientes métodos de la interfaz javax.transaction.UserTransaction:
  • begin
  • commit
  • rollback
Ejemplo:
import java.util.*;
import javax.ejb.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import javax.transaction.*; 
@Stateless
@TransactionManagement(BEAN)
public class BeanStock implements Stock {
@Resource javax.Transaction.UserTransaction mitransaccion;
@Resource javax.sql.DataSource ds1;
public void updateStock(int idstock, double precio) {
Connection con = null;
PreparedStatement prepStmt = null;
try {
con = ds1.getConnection();
mitransaccion.begin();
prepStmt = con.prepareStatement(
"UPDATE Stock set precio = ? where IdStock = ?"); 
prepStmt.setDouble(1, precio);
prepStmt.setInt(2, idstock);
int registrosafectados = prepStmt.executeUpdate();
mitransaccion.commit();
} catch (Exception ex) {
try {
mitransaccion.rollback();
} catch (SystemException ex) {
throw new EJBException ("Rollback ha fallado: " + ex.getMessage();
}
throw new EJBException("La transaccion ha fallado: " + ex.getMessage());
} finally {
try {
prepStmt.close();
con.close();
} catch (SQLException ex) {
throw new EJBException ("Error al cerrar la conexion: " + e.getMessage()); 
}
}
}

No hay comentarios:

Publicar un comentario