PL/SQL v příkladech / Záchytné body

Záchytné body jsou mechanismem uvnitř PL/SQL bloku, který umožňuje rozdělit prováděnou transakci na dílčí celky, neboli milníky. K těmto milníkům se poté lze jednoduše vrátit, aniž bychom přišli o celou transakci.

Nejdříve si zadefinujme pomocnou metodu, která vrátí plat konkrétního zaměstnance.

CREATE OR REPLACE FUNCTION sf_VratPlat(
    p_Zamestnanec_ID NUMBER
) RETURN NUMBER
IS
  l_Plat NUMBER;
BEGIN
  SELECT salary
    INTO l_Plat
    FROM employees
    WHERE employee_id=p_Zamestnanec_ID
  ;
  RETURN l_Plat;
END;
/

A ještě jednu, která plat aktualizuje.

CREATE OR REPLACE PROCEDURE sp_NastavPlat(
    p_Zamestnanec_ID NUMBER
  , p_Plat NUMBER
)
IS
BEGIN
  UPDATE employees
    SET salary=p_Plat
    WHERE (employee_id=p_Zamestnanec_ID)
  ;
END;
/

V prvním kroku nastavíme počáteční plat na 24000, čímž započne transakce. O tuto hodnotu nechceme přijít, ať už se dále v kódu děje cokoliv. Vytvoříme tedy bod obnovy a pojmenujeme ho vnejsi_savepoint

Druhý krok opět nastaví plat, tentokrát na 25500.

Pro ilustraci následuje anonymní blok, který si před prováděním změn vytvoří „svůj vlastní“ milník s názvem vnitrni_savepoint, nastaví plat na 26000 a vyvolá výjimku. Ta je odchycena a zároveň se provede částečné vrácení změň do stavu před začátkem anonymního bloku.

V poslední fázi se opět vyvolá výjimka a vrácení k záchytnému bodu, což anuluje i aktualizaci platu z druhého kroku.

DECLARE
  L_ZAMESTNANEC_ID CONSTANT NUMBER:=100; -- testovací zaměstnanec
  VYJIMKA EXCEPTION;
BEGIN
  sp_NastavPlat(L_ZAMESTNANEC_ID, 24000);
  dbms_output.put_line(sf_VratPlat(L_ZAMESTNANEC_ID)); -- 24000
    
  SAVEPOINT vnejsi_savepoint;
  sp_NastavPlat(L_ZAMESTNANEC_ID, 25500);
  dbms_output.put_line(sf_VratPlat(L_ZAMESTNANEC_ID)); -- 25500

  /* ZAČÁTEK VNITŘNÍHO BLOKU */
  BEGIN
    SAVEPOINT vnitrni_savepoint;
    sp_NastavPlat(L_ZAMESTNANEC_ID, 26000);
    dbms_output.put_line(sf_VratPlat(L_ZAMESTNANEC_ID)); -- 26000
    RAISE VYJIMKA;
  EXCEPTION
    WHEN VYJIMKA THEN
      ROLLBACK TO SAVEPOINT vnitrni_savepoint;
  END;
  /* KONEC VNITŘNÍHO BLOKU */

  dbms_output.put_line(sf_VratPlat(L_ZAMESTNANEC_ID)); -- 25500
  RAISE VYJIMKA;
EXCEPTION
  WHEN VYJIMKA THEN
    ROLLBACK TO SAVEPOINT vnejsi_savepoint;
    dbms_output.put_line(sf_VratPlat(L_ZAMESTNANEC_ID)); -- 24000
END;

Zanechte komentář

Vaše emailová adresa nebude zobrazena. Povinná pole jsou označena *