miércoles, 22 de agosto de 2012

Savepoint


Cuando jugábamos algún juego de aventura había una luz, una bandera o un objeto medio raro que indicaba que si moríamos en ese nivel no tendríamos que hace de nuevo todo el nivel sino que comenzaríamos de ese punto.


Algo así son los savepoint de las bases de datos, si vemos la wikipedia podemos leer:

"Un savepoint (en español, punto de recuperación) es una forma de implementar subtransacciones (también conocidas como transacciones anidadas) dentro de un sistema gestor de base de datos relacional indicando un punto dentro de unatransacción de base de datos que puede ser "rolled back" (devuelta) sin afectar a cualquier trabajo realizado en la transacción antes de que el punto de recuperación fuera creado. Varios savepoints pueden existir dentro de una transacción individual. Los Savepoints son útiles para implementar recuperación de errores complejos en aplicaciones de base de datos — si ocurre un error en el medio de una transacción de múltiples sentencias, la aplicación puede ser capaz de recuperarse del error (devolviendo, "rolling back", hasta un savepoint) sin necesidad de abortar la transacción completa."

Pero como puedo utilizar este punto de recuperación? En Postgres, es como esta definido en el siguiente ejemplo:

BEGIN;
    INSERT INTO table1 VALUES (1);
    SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (2);
    ROLLBACK TO SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (3);
COMMIT;

En el ejemplo el insert con valor 2 no se aplica dadoque hace un rollback al savepoint my_savepoint.

En Oracle es muy similar veamos otro ejemplo:

DECLARE
   emp_id        employees.employee_id%TYPE;
   emp_lastname  employees.last_name%TYPE;
   emp_salary    employees.salary%TYPE;
BEGIN
   SELECT employee_id, last_name, salary INTO emp_id, emp_lastname,
     emp_salary FROM employees WHERE employee_id = 120;
   UPDATE emp_name SET salary = salary * 1.1 WHERE employee_id = emp_id;
   DELETE FROM emp_name WHERE employee_id = 130;
   SAVEPOINT do_insert;
   INSERT INTO emp_name VALUES (emp_id, emp_lastname, emp_salary);
EXCEPTION
   WHEN DUP_VAL_ON_INDEX THEN
      ROLLBACK TO do_insert;
      DBMS_OUTPUT.PUT_LINE('Insert has been rolled back');
END;
/

Luego de correr esta instrucción podemos ejecutar cualquier instrucción y romper todo. Que tenemos un punto donde podemos volver.