Transacciones en Java
Una
transacción es un conjunto de operaciones sobre una base de datos que se deben
ejecutar como una unidad.
Hay
ocasiones en las que es necesario que varias operaciones sobre la base de datos
se realicen en bloque, es decir, que se ejecuten o todas o ninguna, pero no que
se realicen unas sí y otras no.
Si se
ejecutan parcialmente hasta que una da error, el estado de la base de datos
puede quedar inconsistente. En este caso necesitaríamos un mecanismo para
devolverla a su estado anterior, pudiendo deshacer todas las operaciones
realizadas.
Como
ejemplo, supongamos que vamos a reservar un vuelo desde Alicante hasta Sydney.
Para llegar a Sydney tenemos que realizar varias escalas. Tendremos que
reservar un vuelo de Alicante a Madrid, otro de Madrid a Dubai y otro desde
Dubai a Sydney. Si representamos cada reserva como un insert en la base de
datos tendremos las siguientes instrucciones:
try {
.....
s.executeUpdate("INSERT INTO RESERVAS(pasajero, origen, destino) VALUES('Felipe', 'Alicante', 'Madrid')");
s.executeUpdate("INSERT INTO RESERVAS(pasajero, origen, destino) VALUES ('Felipe', 'Madrid', 'Dubai')");
s.executeUpdate("INSERT INTO RESERVAS(pasajero, origen, destino) VALUES('Felipe', 'Dubai', 'Sydney')");
.....
} catch(SQLException e) {
// Se ha producido un error pero no sabemos donde
// ¿Qué operaciones se han realizado? ¿Cómo deshacerlas?
}
Un objeto Connection por defecto
realiza automáticamente cada operación sobre la base de datos. Esto significa
que cada vez que se ejecuta una instrucción, se refleja en la base de datos y
no puede ser deshecha. Por defecto está habilitado el modo auto-commit en la conexión.
Los
siguientes métodos en la interfaz Connection son utilizados
para gestionar las transacciones en la base de datos:
void setAutoCommit(boolean valor)
void commit()
void rollback()
Para iniciar
una transacción deshabilitamos el modo auto-commit mediante el método setAutoCommit(false). Esto nos
da el control sobre lo que se realiza y cuándo se realiza.
Una llamada
al método commit() realizará todas las instrucciones emitidas desde la última vez que se
invocó el método commit().
Una llamada
a rollback() deshará todos los cambios realizados desde el último commit(). Una vez se ha
emitido una instrucción commit(), esas transacciones
no pueden deshacerse con rollback().
try {
.....
conexion.setAutoCommit(false);
s.executeUpdate("INSERT INTO RESERVAS(pasajero, origen, destino) VALUES('Felipe', 'Alicante', 'Madrid')");
s.executeUpdate("INSERT INTO RESERVAS(pasajero, origen, destino) VALUES ('Felipe', 'Madrid', 'Dubai')");
s.executeUpdate("INSERT INTO RESERVAS(pasajero, origen, destino) VALUES('Felipe', 'Dubai', 'Sydney')");
conexion.commit();
.....
} catch(SQLException e) {
if(conexion!=null){
try {
conexion.rollback();
}catch (SQLException ex) {
System.out.println(ex.toString());
}
}
}
Otro
ejemplo de transacción: Tenemos un fragmento de código que crea un pedido, actualiza el
inventario y crea un registro de envíos. Si falla la creación de un registro de
envíos no se debe crear el pedido. En ese caso, los efectos de las
instrucciones SQL correspondientes a las dos primeras tareas (crear un pedido y
actualizar el inventario) deben deshacerse.
try {
Class.forName("com.mysql.jdbc.Driver");
conexion = DriverManager.getConnection("jdbc:mysql://localhost/prueba","root","1daw");
conexion.setAutoCommit(false); ////// ----->> Desactivamos auto commit
Statement st = conexion.createStatement();
// Crear un pedido
st.executeUpdate("INSERT INTO PEDIDOS(.......) VALUES(.....)");
// Actualizar el inventario
st.executeUpdate("UPDATE TABLE INVENTARIO SET stock = ...... WHERE PRODUCT ID = .....");
// Crear un registro de envíos si se cumple una determinada condición
if (Condicion que debe cumplirse) {
st.executeUpdate("INSERT INTO ENVIOS(....) VALUES(...)");
conexion.commit(); ///// ---->> reflejar las operaciones en la base de datos
} else {
conexion.rollback(); ///// -----> Deshacer operaciones
}
} catch (SQLException e) { //Si se produce una Excepción deshacemos las operaciones
System.out.println(e.toString());
if(conexion!=null){
try {
conexion.rollback();///// -----> Deshacer operaciones
} catch (SQLException ex) {
System.out.println(ex.toString());
}
}
} catch (ClassNotFoundException e) {
System.out.println(e.toString());
} finally {
try {
if (conexion != null) {
conexion.close();
}
} catch (SQLException ex) {
System.out.println(ex.toString());
}
}
Muchas gracias.
ResponderEliminarMuchas gracias, muy bien explicado
ResponderEliminarDe nada Valentina. Gracias por el comentario.
Eliminaraaaa pillin a las mujeres si les respondes eee
EliminarY bueno... vivo el muchacho. :-)
EliminarSi tengo un formulario que ingresa nuevas filas en diferentes tablas esta es la mejor forma de hacerlo ?
ResponderEliminarSi, en caso de que esos ingresos a diferentes tablas estén relacionados de alguna manera.
Eliminary como sería el caso para una venta y el detalle_venta donde este último requiere del ID de la venta?? me darías un ejemplo? Gracias
ResponderEliminarUn gran aporte, me gusta tu forma de explicar este tema...
ResponderEliminarMuchas Gracias