Una transacción es un conjunto de ordenes SQL, que el programador agrupa por razones de la lógica del dominio. Una transacción se define para cumplir las restricciones de integridad de la base de datos. Veamos un ejemplo, supongamos que tenemos que diseñar y programar una aplicación en la que dos de sus requisitos son:
Supongamos que tenemos una tabla, denominada tab_venta, donde insertamos las ventas y otra (tab_usu) en la que se inserta el usuario del sistema que ha registrado la venta. La idea de esta estructura es poder registrar todas las ventas y además controlar o monitorizar lo que hacen los usuarios del sistema, por ello, en tab_usu registramos las operaciones realizadas por los usuarios. La regla de integridad es: "SI realizamos una operación (INSERT, DELETE, UPDATE) sobre tab_venta, entonces se debe registrar la operación y el nombre de usuario sobre tab_usu, a la inversa sólo se produce un registro sobre tab_usu si previamente se ha realizado la operación sobre tab_venta".
En el ejemplo se puede observar que el registro de la venta y el registro del usuario estan intimamente unidos (agrupados), sólo se produce uno si se puede producir el otro y viceversa. En terminos de tablas esto significa que debemos definir una transacción, que se compone de la orden sobre tab_venta y de la orden sobre tab_usu, de tal forma que se cumpla:
Con este sencillo ejemplo tenemos los conceptos clave en el manejo de transacciones:
Como norma general una transacción queda delimitada por la ejecución de una orden de commit o rollback, o bien
la apertura o cierre de conexión. Cualquiera de estos eventos determina el inicio o fin de la transacción.
Autocommit
Por defecto una conexión (Connection) no admite transacciones, es decir, no podemos "ligar" o "agrupar" ordenes. Dicho de otra forma todas las ordenes se ejecutan en modo autocommit: cada orden se confirma individualmente y se vuelca en la base de datos. Con el siguiente código podemos preguntar a la conexión si está en modo autocommit y, si es el caso, ponerla en modo no-autocommit. El siguiente paso es crear el objeto del tipo Statement
if (con.getAutoCommit() ) con.setAutoCommit( false ); Statement sentencia = con.createStatement( );
A continuación se realizan las ordenes de la transsacción (el final de la transacción queda delimitado por la llamada a commit()):
stat.executeUpdate( "INSERT INTO tab_venta VALUES ..."); stat.executeUpdate( "INSERT INTO tab_usu VALUES ..."); con.commit();
Pero si algo falla debemos llamar a rollback (deshacer). Lo más normal es ejecutar dicha llamada al capturar la excepción SQLException. En nuestro pequeño ejemplo el rollback lo hacemos en el método deshacer(), de esta forma lo tenemos disponible para todas nuestras clases:
void metodo() {
try {
stat.executeUpdate( "INSERT INTO tab_venta VALUES ...");
stat.executeUpdate( "INSERT INTO tab_usu VALUES ...");
con.commit();
catch (SQLException e) {
deshacer();
}
}
void deshacer( ) {
try { con.rollback(); }
catch (SQLException e) { System.out.println("Error. No hemos podido deshacer." + e.getMessage() ); }
}
El uso de rollback() exige el manejo de SQLException.
Nota final: el tratamiento de transacciones en MySQL anterior a 5.1 exige tablas del tipo InnoDB. Para versiones posteriores esta capacidad se encuentra en todos los tipos de tablas.