Trigger — BEFORE, AFTER, INSERT, UPDATE, DELETE
Muammodan boshlaylik
Ikki talab:
- Audit: mahsulot narxi qachon, qanchadan qanchaga o'zgarganini saqlash kerak. Narx admin paneldan, import skriptidan, API dan va qo'lda Workbench dan o'zgaradi.
- Himoya: narx hech qachon nolga yoki manfiyga tushmasin.
Har bir joyda "narx o'zgarsa — tarixga yoz" kodini qo'shish mumkin. Lekin bitta joyda unutilsa — tarix to'liq bo'lmaydi. Va Workbench dan qo'lda o'zgartirishni ilova umuman ko'rmaydi.
Trigger — jadvalda ma'lum hodisa (INSERT, UPDATE, DELETE) bo'lganda bazaning o'zi avtomatik bajaradigan kod. Ma'lumot qaysi yo'l bilan o'zgarmasin — trigger ishlaydi.
Trigger tuzilishi
CREATE TRIGGER nom
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON jadval
FOR EACH ROW
BEGIN
...
END;
- BEFORE — o'zgarishdan oldin: qiymatlarni tekshirish yoki o'zgartirish
- AFTER — o'zgarishdan keyin: boshqa jadvallarga yozish (audit, hisoblagichlar)
- FOR EACH ROW — har bir ta'sirlangan qator uchun alohida (MySQL da faqat shu)
OLD va NEW
Trigger ichida qatorning eski va yangi qiymatlari:
| Hodisa | OLD |
NEW |
|---|---|---|
INSERT |
— | Qo'shilayotgan qator |
UPDATE |
O'zgarishdan oldingi | O'zgarishdan keyingi |
DELETE |
O'chirilayotgan qator | — |
1-misol: audit — narx tarixi
CREATE TABLE narx_tarixi (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
mahsulot_id INT UNSIGNED NOT NULL,
eski_narx INT UNSIGNED NOT NULL,
yangi_narx INT UNSIGNED NOT NULL,
kim VARCHAR(100) NOT NULL,
qachon DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
DELIMITER //
CREATE TRIGGER trg_mahsulot_narx_audit
AFTER UPDATE ON mahsulotlar
FOR EACH ROW
BEGIN
IF NEW.narx <> OLD.narx THEN
INSERT INTO narx_tarixi (mahsulot_id, eski_narx, yangi_narx, kim)
VALUES (NEW.id, OLD.narx, NEW.narx, CURRENT_USER());
END IF;
END //
DELIMITER ;
UPDATE mahsulotlar SET narx = 11900000 WHERE id = 1;
UPDATE mahsulotlar SET soni = 10 WHERE id = 1; -- narx o'zgarmadi — yozilmaydi
SELECT * FROM narx_tarixi;
+----+-------------+-----------+------------+----------------+---------------------+
| id | mahsulot_id | eski_narx | yangi_narx | kim | qachon |
+----+-------------+-----------+------------+----------------+---------------------+
| 1 | 1 | 12500000 | 11900000 | root@localhost | 2026-11-04 15:10:22 |
+----+-------------+-----------+------------+----------------+---------------------+
IF NEW.narx <> OLD.narx — faqat narx haqiqatan o'zgarganda. Aks holda har bir soni o'zgarishi ham tarixga tushardi.
[!INFO]
CURRENT_USER()— MySQL foydalanuvchisi (dokon_app@%), saytdagi admin emas. Haqiqiy foydalanuvchini bilish uchun ilova sessiya o'zgaruvchisini o'rnatadi:SET @app_user = 'admin:42';va trigger@app_userni yozadi.
2-misol: tekshirish va tuzatish — BEFORE
DELIMITER //
CREATE TRIGGER trg_mahsulot_tekshir
BEFORE UPDATE ON mahsulotlar
FOR EACH ROW
BEGIN
IF NEW.narx = 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Narx nol bo''lishi mumkin emas';
END IF;
-- Nomni avtomatik tozalash
SET NEW.nom = TRIM(NEW.nom);
-- Narx 50% dan ko'proq tushsa — ehtimol xato
IF NEW.narx < OLD.narx * 0.5 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Narx 50% dan ortiq tushirildi — tasdiqlash kerak';
END IF;
END //
DELIMITER ;
UPDATE mahsulotlar SET narx = 1000 WHERE id = 3;
-- ERROR 1644 (45000): Narx 50% dan ortiq tushirildi — tasdiqlash kerak
BEFORE triggerda SET NEW.ustun = ... — yoziladigan qiymatni o'zgartirish mumkin. AFTER da — yo'q (qator allaqachon yozilgan).
Oddiy qoidalar uchun CHECK cheklovi (6-dars) soddaroq. Trigger — OLD va NEW ni solishtirish kerak bo'lganda (CHECK faqat yangi qiymatni ko'radi).
3-misol: hisoblagichni yangilash
Mahsulotlar sonini toifa jadvalida saqlash (denormalizatsiya, 47-dars):
ALTER TABLE toifalar ADD COLUMN mahsulotlar_soni INT UNSIGNED NOT NULL DEFAULT 0;
DELIMITER //
CREATE TRIGGER trg_mahsulot_qoshildi AFTER INSERT ON mahsulotlar
FOR EACH ROW
BEGIN
UPDATE toifalar SET mahsulotlar_soni = mahsulotlar_soni + 1 WHERE id = NEW.toifa_id;
END //
CREATE TRIGGER trg_mahsulot_ochirildi AFTER DELETE ON mahsulotlar
FOR EACH ROW
BEGIN
UPDATE toifalar SET mahsulotlar_soni = mahsulotlar_soni - 1 WHERE id = OLD.toifa_id;
END //
CREATE TRIGGER trg_mahsulot_toifa_ozgardi AFTER UPDATE ON mahsulotlar
FOR EACH ROW
BEGIN
IF NOT (NEW.toifa_id <=> OLD.toifa_id) THEN
UPDATE toifalar SET mahsulotlar_soni = mahsulotlar_soni - 1 WHERE id = OLD.toifa_id;
UPDATE toifalar SET mahsulotlar_soni = mahsulotlar_soni + 1 WHERE id = NEW.toifa_id;
END IF;
END //
DELIMITER ;
Uchta hodisani ham hisobga olish kerak — bittasini unutsangiz, hisoblagich asta-sekin noto'g'ri bo'lib qoladi. <=> — NULL larni ham to'g'ri solishtirish (10-dars).
Trigger va tranzaksiya
Trigger — o'zgarishni keltirib chiqargan so'rov bilan bitta tranzaksiyada ishlaydi:
- Trigger xato bersa (
SIGNAL) — aslUPDATEham bekor qilinadi - Asl tranzaksiya
ROLLBACKqilinsa — trigger qilgan o'zgarishlar ham bekor bo'ladi
Audit tarixi va hisoblagichlar asl ma'lumot bilan doim mos.
Boshqarish
SHOW TRIGGERS FROM dokon;
SHOW CREATE TRIGGER trg_mahsulot_narx_audit\G
DROP TRIGGER IF EXISTS trg_mahsulot_narx_audit;
MySQL 8 da bir jadvalda bir xil hodisa uchun bir nechta trigger bo'lishi mumkin — tartibi FOLLOWS / PRECEDES bilan.
Ehtiyot bo'ling
Trigger — kuchli, lekin ko'rinmas vosita.
1. Yashirin xatti-harakat. Dasturchi UPDATE mahsulotlar yozadi va 3 ta boshqa jadval o'zgaradi — buni kodga qarab bilib bo'lmaydi. Debug paytida "bu qator qayerdan paydo bo'ldi?" degan savol soatlab vaqt oladi.
2. Tezlik. Trigger har bir qator uchun ishlaydi. UPDATE mahsulotlar SET narx = narx * 1.1 — 50 000 qator → 50 000 ta trigger chaqiruvi, 50 000 ta INSERT audit jadvaliga.
3. Zanjir. Trigger boshqa jadvalni o'zgartiradi, u yerda ham trigger bor... Trigger o'zi turgan jadvalni o'zgartira olmaydi (ERROR 1442), lekin boshqalar orqali murakkab zanjir hosil bo'lishi mumkin.
4. TRUNCATE va DROP — DELETE trigger larini ishga tushirmaydi. Foreign key CASCADE orqali o'chirilgan qatorlar ham trigger ni ishga tushirmaydi.
Qachon ishlatish
✅ Yaxshi nomzodlar:
- Audit / o'zgarishlar tarixi — har qanday manbadan
- Qo'shimcha himoya —
OLDvaNEWsolishtirish kerak bo'lgan qoidalar - Oddiy denormalizatsiya hisoblagichlari
❌ Yomon nomzodlar:
- Biznes jarayonlari (email yuborish, buyurtma holatini o'zgartirish) — ilovada
- Murakkab mantiq — ilovada yoki procedure da
- Juda ko'p yoziladigan jadvallar
Trigger yaratsangiz — hujjatlashtiring: jadval izohida yoki loyiha README sida.
ALTER TABLE mahsulotlar COMMENT = 'Triggerlar: narx audit (narx_tarixi), toifa hisoblagich';
Nima uchun shunday?
Nima uchun trigger lar "yomon amaliyot" deb tanqid qilinadi, agar ular bunchalik foydali bo'lsa?
Chunki ular sababni oqibatdan ajratadi. Kod o'qiyotgan odam UPDATE mahsulotlar SET narx = ? ni ko'radi va faqat bitta jadval o'zgaradi deb o'ylaydi. Haqiqatda esa audit yozuvi, hisoblagich yangilanishi va, ehtimol, xato. Bu "kutilmagan ta'sirlar" katta jamoada xatolarga olib keladi. Lekin audit kabi holatlarda aynan shu xususiyat — afzallik: ilova kodini chetlab o'tib bo'lmaydi. Trigger — "majburiy" qoidalar uchun, "qulay" avtomatlashtirish uchun emas.
Xulosa
Eslab qoling:
CREATE TRIGGER nom BEFORE|AFTER INSERT|UPDATE|DELETE ON jadval FOR EACH ROWOLD— eski qiymat,NEW— yangi;INSERTdaOLDyo'q,DELETEdaNEWyo'qBEFORE— tekshirish (SIGNAL) vaSET NEW.x = ...;AFTER— boshqa jadvallarga yozish- Asl so'rov bilan bitta tranzaksiyada
- Har bir qator uchun ishlaydi — ommaviy o'zgarishlarda sekin
TRUNCATEvaCASCADEtrigger ni ishga tushirmaydi- Audit va qat'iy himoya uchun; biznes jarayonlar — ilovada
- Hujjatlashtiring — trigger lar ko'rinmas
Keyingi dars
44-dars: Event Scheduler — avtomatik vazifalar