Transacciones


Introducción al concepto de transacción

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:

  1. El usuario podrá registrar las ventas, además podrá modificar o borrar dicho registro.
  2. El sistema debe registrar las acciones realizadas por el usuario, de tal forma que quede constancia de quién ha realizado las operaciones de inserción, borrado y actualización. Dicho de forma no técnica, hay que vigilar a los usuarios.

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:

  1. Si ha fallado la orden sobre tab_venta no se produce el registro sobre tab_usu. Cumplir esta regla es fácil, un sencillo condicional que puede realizar el programador.
  2. Si se ha producido la inserción sobre tab_venta, pero falla la inserción sobre tab_usu, entonces necesitamos un mecanismo fácil para deshacer la inserción de la venta. Recordemos que estamos ante dos ordenes ligadas, es decir, sólo nos sirve que se ejecuten exitósamente las dos. Para esta operación de "deshacer" resulta mucho más fácil y seguro que la realize el gestor de base de datos que el programador.
  3. Si las dos operaciones son exitosas se confirman.

Con este sencillo ejemplo tenemos los conceptos clave en el manejo de transacciones:

  1. La definición de las ordenes que componen la transacción (delimitar la transacción).
  2. Commit o confirmación de que todas las ordenes se realizan.
  3. Rollback o dehacer las ordenes en caso de que alguna falle.

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( );

Commit y Rollback

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.


Volver al índice