PostgreSQL / Trigger үндэс

Trigger үндэс

Өгөгдлийн санд ямар нэгэн үйлдэл болох үед — жишээлбэл шинэ мөр нэмэгдэх, мөр өөрчлөгдөх, устгагдах — автоматаар ажиллах логик бичиж болно. Үүнийг trigger гэнэ. Trigger нь application layer-аас үл хамааран өгөгдлийн санд шууд ажилладаг тул дүрмүүдийг нэг газар нэгтгэж, алдаа гарах эрсдлийг бууруулдаг.

Trigger хэрхэн ажилладаг вэ?

Trigger нь хоёр хэсгээс бүрдэнэ:

  1. Trigger функцRETURNS TRIGGER буцаадаг PL/pgSQL функц
  2. Trigger тодорхойлолт — хэзээ, ямар үйлдлийн үед функцийг дуудахыг заана

Жишээ болгон дараах хүснэгтүүдийг ашиглая:

sql
CREATE TABLE products (
    id           SERIAL PRIMARY KEY,
    name         TEXT NOT NULL,
    price        NUMERIC NOT NULL,
    stock        INT NOT NULL DEFAULT 0,
    updated_at   TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE audit_log (
    id          SERIAL PRIMARY KEY,
    table_name  TEXT NOT NULL,
    action      TEXT NOT NULL,
    old_data    JSONB,
    new_data    JSONB,
    changed_at  TIMESTAMPTZ DEFAULT NOW()
);

BEFORE trigger — үйлдлийн өмнө

BEFORE trigger нь INSERT/UPDATE/DELETE гүйцэтгэгдэхийн өмнө ажиллана. NEW бичлэгийг өөрчилж болдог тул автоматаар утга дүүргэхэд тохиромжтой:

sql
-- updated_at-г автоматаар шинэчлэх trigger функц
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
    NEW.updated_at := NOW();
    RETURN NEW;
END;
$$;

-- Trigger тодорхойлолт: UPDATE болох бүрт дуудна
CREATE TRIGGER trg_products_updated_at
    BEFORE UPDATE ON products
    FOR EACH ROW
    EXECUTE FUNCTION set_updated_at();

-- Туршиж үзэх
INSERT INTO products (name, price, stock) VALUES ('Утас', 850000, 10);
UPDATE products SET price = 900000 WHERE id = 1;

-- updated_at автоматаар солигдсон
SELECT name, price, updated_at FROM products WHERE id = 1;

NEW бол шинэ утгуудыг агуулсан тусгай хувьсагч. RETURN NEW гэж буцаавал үйлдэл үргэлжилнэ. RETURN NULL гэвэл үйлдлийг цуцална.

AFTER trigger — үйлдлийн дараа

AFTER trigger нь үйлдэл амжилттай дууссаны дараа ажиллана. Audit log бичих, нөөц системд мэдэгдэл илгээх зэрэгт хэрэглэнэ:

sql
-- Өөрчлөлтийн түүх бичдэг trigger функц
CREATE OR REPLACE FUNCTION log_product_changes()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
    IF TG_OP = 'INSERT' THEN
        INSERT INTO audit_log (table_name, action, new_data)
        VALUES ('products', 'INSERT', ROW_TO_JSON(NEW)::JSONB);

    ELSIF TG_OP = 'UPDATE' THEN
        INSERT INTO audit_log (table_name, action, old_data, new_data)
        VALUES ('products', 'UPDATE',
                ROW_TO_JSON(OLD)::JSONB,
                ROW_TO_JSON(NEW)::JSONB);

    ELSIF TG_OP = 'DELETE' THEN
        INSERT INTO audit_log (table_name, action, old_data)
        VALUES ('products', 'DELETE', ROW_TO_JSON(OLD)::JSONB);
    END IF;

    RETURN NULL;  -- AFTER trigger-д RETURN NULL байж болно
END;
$$;

-- INSERT, UPDATE, DELETE бүгдэнд ажиллуулах
CREATE TRIGGER trg_products_audit
    AFTER INSERT OR UPDATE OR DELETE ON products
    FOR EACH ROW
    EXECUTE FUNCTION log_product_changes();

TG_OP нь одоогийн үйлдлийн нэрийг агуулдаг тусгай хувьсагч ('INSERT', 'UPDATE', 'DELETE'). OLD бол үйлдлийн өмнөх утгуудыг агуулна.

Trigger шалгах ба устгах

sql
-- Бүх trigger-ийг харах
SELECT trigger_name, event_manipulation, event_object_table, action_timing
FROM information_schema.triggers
WHERE trigger_schema = 'public';

-- Trigger идэвхгүй болгох
ALTER TABLE products DISABLE TRIGGER trg_products_audit;

-- Дахин идэвхжүүлэх
ALTER TABLE products ENABLE TRIGGER trg_products_audit;

-- Trigger устгах
DROP TRIGGER trg_products_audit ON products;

-- Trigger функц устгах
DROP FUNCTION log_product_changes();

Trigger нь хэт олон байвал debug хийхэд хэцүү болдог. Зөвхөн үнэхээр шаардлагатай газарт — audit log, автомат тооцоо, хязгаарлалт — ашиглах нь зөв хандлага юм.

Дараагийн хичээлд:

Олон SQL үйлдлийг нэг transaction болгон нэгтгэж, бүгдийг нэгэн зэрэг амжилттай дуусгах эсвэл бүгдийг цуцлах ACID баталгааг сурна.