CodeGym /Kurslar /SQL SELF /Prosedurların və funksiyaların tranzaksiyalar daxilində ç...

Prosedurların və funksiyaların tranzaksiyalar daxilində çağırılması

SQL SELF
Səviyyə , Dərs
Mövcuddur

Müasir verilənlər bazası sistemlərində biznes-məntiq tez-tez server tərəfində — prosedurlar və funksiyalar vasitəsilə yazılır. PostgreSQL ilə işləyərkən, xüsusilə 11+ versiyasında prosedurlar gəldikdən sonra, funksiyalarla prosedurlar arasındakı fərqi və onların tranzaksiyalarla necə işlədiyini başa düşmək vacibdir.

Aşağıda sənə PostgreSQL 17-də tranzaksiya mexanikası, iç-içə çağırışlar və prosedur/funksiya daxilində dəyişikliklərin qismən geri qaytarılması barədə əsas faktları danışacam, rəsmi sənədlərə və aktual məhdudiyyətlərə əsaslanaraq.

Açar anlayışlar: funksiyalar vs prosedurlar

Funksiya (CREATE FUNCTION) — həmişə bir xarici tranzaksiya çərçivəsində işləyir; funksiyalar daxilində açıq tranzaksiya komandalarından (BEGIN, COMMIT, ROLLBACK, SAVEPOINT) istifadə etmək olmaz.

  • İstənilən dəyişikliklər yalnız xarici tranzaksiya səviyyəsində təsdiqlənir və ya geri qaytarılır.
  • Funksiya daxilində "qismən geri qaytarma" üçün BEGIN ... EXCEPTION ... END istifadə olunur, amma bu, funksiya daxilində commit etməyə imkan vermir.

Prosedur (CREATE PROCEDURE) — tranzaksiyalara birbaşa serverdə nəzarət etmək üçün gəlib (məsələn, qismən commit, mərhələ rollback və s.).

  • Prosedurlarda (PL/pgSQL) COMMIT, ROLLBACK, SAVEPOINT, RELEASE SAVEPOINT istifadə etmək olar.
  • VACİBDİR: PL/pgSQL-prosedurunda ROLLBACK TO SAVEPOINT istifadə etmək olmaz (sintaksis xətası verəcək).
  • Prosedurları yalnız ayrıca SQL komandası ilə CALL ... çağırmaq olar, SELECT və ya başqa funksiyaların içində yox.

Bir proseduru/funksiyanı digərindən necə çağırmaq olar?

Funksiyalar başqa funksiyaları adi adla çağırışla "şəffaf" şəkildə çağırır:

-- Nümunə: endirimi hesablamaq üçün funksiya
CREATE OR REPLACE FUNCTION calculate_discount(order_total NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
    IF order_total >= 100 THEN
        RETURN order_total * 0.1;
    ELSE
        RETURN 0;
    END IF;
END;
$$ LANGUAGE plpgsql;

-- Sifariş işləmə funksiyası başqa funksiyanı çağırır
CREATE OR REPLACE FUNCTION process_order(order_id INT, order_total NUMERIC)
RETURNS VOID AS $$
DECLARE
    discount NUMERIC;
BEGIN
    discount := calculate_discount(order_total);
    RAISE NOTICE 'Endirim: %', discount;
    INSERT INTO orders_log (order_id, order_total, discount)
    VALUES (order_id, order_total, discount);
END;
$$ LANGUAGE plpgsql;

Hər şey bir xarici tranzaksiya çərçivəsində icra olunur! İstənilən funksiyada xəta olsa, bütün dəyişikliklər geri qaytarılacaq.

Prosedurların çağırılması və iç-içə tranzaksiyalar

Prosedurları başqa prosedurların içində CALL ... komandası ilə çağırmaq olar (PostgreSQL 17-də CALL proc1() -> CALL proc2() kimi çağırış stack-i mümkündür), amma tranzaksiya qaydaları dəyişmir:

  • Tranzaksiya komandaları (COMMIT, ROLLBACK, SAVEPOINT, RELEASE SAVEPOINT) yalnız prosedurların ən üst səviyyəsində işləyir.
  • Əgər tranzaksiya idarəsi olan prosedur artıq aktiv açıq tranzaksiyada çağırılırsa (məsələn, autocommit olmayan client-dən), COMMIT/SAVEPOINT işlətmək cəhdində xəta olacaq.
VACİBDİR:

prosedurları funksiyaların və ya anonim blokların (DO ...) içində başlatmaq olmaz. Yalnız ayrıca CALL komandası ilə.

Tranzaksiya idarəsi ilə prosedur nümunəsi

-- Mərhələli commit ilə prosedur (yalnız autocommit rejimində işləyir)
CREATE PROCEDURE process_batch_orders()
LANGUAGE plpgsql
AS $$
DECLARE
    rec RECORD;
BEGIN
    FOR rec IN SELECT order_id, order_total FROM incoming_orders LOOP
        BEGIN
            -- Hər partiya məlumatı ayrıca saxlayırıq
            INSERT INTO orders (order_id, total) VALUES (rec.order_id, rec.order_total);
        EXCEPTION WHEN OTHERS THEN
            INSERT INTO order_errors(order_id, err_text) VALUES (rec.order_id, SQLERRM);
        END;
        COMMIT;
    END LOOP;
END;
$$;

-- Prosedurun çağırılması
CALL process_batch_orders();

Hər COMMIT-dən sonra avtomatik yeni tranzaksiya başlayır.

PL/pgSQL-də qismən rollback (savepoint-ə bənzər davranış)

PL/pgSQL (həm funksiyalarda, həm prosedurlarda) ROLLBACK TO SAVEPOINT komandasını dəstəkləmir.

Kodun bir hissəsinin dəyişikliklərini geri qaytarmaq üçün yalnız BEGIN ... EXCEPTION ... END bloku istifadə olunur:

BEGIN
    -- hansısa əməliyyatlar
    BEGIN
        -- potensial xətalı əməliyyat
    EXCEPTION WHEN OTHERS THEN
        -- bu blokdakı bütün dəyişikliklər geri qaytarılacaq
        RAISE NOTICE 'Blok daxilində rollback!';
    END;
END;

Prosedurlarda həmçinin SAVEPOINTRELEASE SAVEPOINT istifadə etmək olar, amma ROLLBACK TO SAVEPOINT yox. Onların mənası mərhələləri ayırmaqdır, amma idarə yalnız exception-larla mümkündür.

Məhdudiyyətlər və ən yaxşı təcrübələr

  1. Funksiyalar — yalnız atomik əməliyyatlar: ya hamısı, ya heç nə. Nə isə səhv olsa — bütün dəyişikliklər geri qaytarılır.
  2. Prosedurlar — yalnız CALL ilə: və yalnız ayrıca SQL komandası ilə, SELECT/funksiya içindən yox. İç-içə tranzaksiya idarəsi mümkündür, amma PL/pgSQL məhdudiyyətlərinə ciddi əməl etməklə.
  3. Qismən rollback — yalnız EXCEPTION ilə: rəsmi tövsiyə olunan və dəstəklənən yeganə yol (SAVEPOINT-ə bənzər).
  4. İç-içə prosedurlar yalnız CALL ilə tranzaksiyalara nəzarət edə bilər: əks halda xəta olacaq.

Məntiq və tranzaksiyaların qarşılıqlı təsiri barədə suallar

Funksiya daxilində "iç-içə" tranzaksiya edə bilərəm?

Xeyr. Hər şey bir tranzaksiyada icra olunur. Qismən rollback üçün — yalnız EXCEPTION blokları.

Funksiya və ya anonim blok daxilində COMMIT/ROLLBACK edə bilərəm?

Xeyr, bu sintaksis xətasıdır. Prosedurlardan istifadə et.

Funksiyadan proseduru çağırmaq olar?

Xeyr, yalnız CALL komandası ilə. Funksiya/SELECT-dən — olmaz.

Prosedurda ROLLBACK TO SAVEPOINT etmək olar?

Xeyr! PL/pgSQL-də bu qadağandır. EXCEPTION bloklarından istifadə et.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION