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 ... ENDistifadə 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 SAVEPOINTistifadə etmək olar. - VACİBDİR: PL/pgSQL-prosedurunda
ROLLBACK TO SAVEPOINTistifadə etmək olmaz (sintaksis xətası verəcək). - Prosedurları yalnız ayrıca SQL komandası ilə
CALL ...çağırmaq olar,SELECTvə 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/SAVEPOINTişlətmək cəhdində xəta olacaq.
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 SAVEPOINT və RELEASE 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
- 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.
- 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ə.
- Qismən rollback — yalnız EXCEPTION ilə: rəsmi tövsiyə olunan və dəstəklənən yeganə yol (SAVEPOINT-ə bənzər).
- İç-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.
GO TO FULL VERSION