MySQL / Trigger

Trigger

Trigger нь хүснэгтэд өөрчлөлт орох үед автоматаар ажиллах тусгай procedure. Хэрэглэгч буюу аппликейшн дуудах шаардлагагүй — MySQL өөрөө ажиллуулна.

Trigger-ийн бүтэц

sql
CREATE TRIGGER trigger_name
  {BEFORE | AFTER} {INSERT | UPDATE | DELETE}
  ON table_name
  FOR EACH ROW
BEGIN
  -- ажиллах код
END;

6 төрлийн trigger байдаг:

| | INSERT | UPDATE | DELETE | | ---------- | ------------- | ---------------- | -------------- | | BEFORE | Нэмэхийн өмнө | Өөрчлөхийн өмнө | Устгахын өмнө | | AFTER | Нэмсний дараа | Өөрчилсний дараа | Устгасны дараа |

NEW ба OLD утгууд

| Үйлдэл | NEW | OLD | | ------ | ----------------------- | ---------------------- | | INSERT | Шинэ мөрийн утга | Байхгүй (NULL) | | UPDATE | Өөрчлөлтийн дараах утга | Өөрчлөлтийн өмнөх утга | | DELETE | Байхгүй (NULL) | Устгагдсан мөрийн утга |

AFTER INSERT — нэмсний дараа

sql
-- Хэрэглэгч бүртгүүлэхэд профайл автоматаар үүсгэх
DELIMITER //

CREATE TRIGGER after_user_insert
  AFTER INSERT ON users
  FOR EACH ROW
BEGIN
  INSERT INTO profiles (user_id, display_name, created_at)
  VALUES (NEW.id, NEW.username, NOW());
END //

DELIMITER ;

-- Одоо users-д нэмэхэд profiles автоматаар нэмэгдэнэ
INSERT INTO users (username, email) VALUES ('Болд', 'bold@example.com');
-- profiles хүснэгтэд тухайн хэрэглэгчийн мөр үүснэ

BEFORE INSERT — нэмэхийн өмнө

BEFORE trigger нь NEW утгыг өөрчлөх боломжтой — өгөгдөл стандартчилах, шалгахад хэрэглэнэ:

sql
DELIMITER //

CREATE TRIGGER before_user_insert
  BEFORE INSERT ON users
  FOR EACH ROW
BEGIN
  -- И-мэйлийг жижиг үсгээр хөрвүүлж хадгалах
  SET NEW.email = LOWER(TRIM(NEW.email));
  -- Хэрэглэгчийн нэрийн эхний үсгийг том болгох
  SET NEW.username = CONCAT(
    UPPER(SUBSTRING(NEW.username, 1, 1)),
    LOWER(SUBSTRING(NEW.username, 2))
  );
END //

DELIMITER ;

AFTER UPDATE — өөрчилсний дараа

sql
-- Бараа нөөц тодорхой хэмжээнд хүрэхэд мэдэгдэл үүсгэх
DELIMITER //

CREATE TRIGGER after_product_update
  AFTER UPDATE ON products
  FOR EACH ROW
BEGIN
  IF NEW.stock < 10 AND OLD.stock >= 10 THEN
    INSERT INTO alerts (product_id, message, created_at)
    VALUES (NEW.id, CONCAT(NEW.name, ': нөөц багасаж байна — ', NEW.stock, ' үлдсэн'), NOW());
  END IF;
END //

DELIMITER ;

OLD.stock >= 10 AND NEW.stock < 10 — шилжилтийн мөчийг барина. Байнга биш, зааглах үед л ажиллана.

BEFORE DELETE — устгахын өмнө

sql
-- Устгалтыг хориглох
DELIMITER //

CREATE TRIGGER before_order_delete
  BEFORE DELETE ON orders
  FOR EACH ROW
BEGIN
  IF OLD.status = 'paid' THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Төлбөр хийгдсэн захиалга устгах боломжгүй';
  END IF;
END //

DELIMITER ;

DELETE FROM orders WHERE id = 1;
-- ERROR: Төлбөр хийгдсэн захиалга устгах боломжгүй

SIGNAL SQLSTATE '45000' нь өөрчлөлтийг зогсоож алдааны мэдэгдэл буцаана.

Audit log — өөрчлөлтийн бүртгэл

Ямар өгөгдөл, хэзээ, хэн өөрчилснийг хадгалах нь аюулгүй байдалд чухал:

sql
-- Audit log хүснэгт
CREATE TABLE salary_audit (
  id         INT PRIMARY KEY AUTO_INCREMENT,
  employee_id INT,
  old_salary  DECIMAL(10,2),
  new_salary  DECIMAL(10,2),
  changed_at  DATETIME DEFAULT NOW(),
  changed_by  VARCHAR(100)
);

-- Цалин өөрчлөгдөх бүрт бүртгэх
DELIMITER //

CREATE TRIGGER after_salary_update
  AFTER UPDATE ON employees
  FOR EACH ROW
BEGIN
  IF OLD.salary != NEW.salary THEN
    INSERT INTO salary_audit (employee_id, old_salary, new_salary, changed_by)
    VALUES (OLD.id, OLD.salary, NEW.salary, USER());
  END IF;
END //

DELIMITER ;

-- Цалин өөрчлөх
UPDATE employees SET salary = 2500000 WHERE id = 5;

-- Бүртгэл шалгах
SELECT * FROM salary_audit;

USER() нь MySQL-д одоо холбогдсон хэрэглэгчийн нэрийг буцаана.

Trigger харах ба устгах

sql
-- Database-н бүх trigger жагсаах
SHOW TRIGGERS FROM myshop;

-- Тодорхой хүснэгтийн trigger
SHOW TRIGGERS FROM myshop WHERE `Table` = 'orders';

-- Trigger устгах
DROP TRIGGER IF EXISTS after_user_insert;

Trigger-ийн хязгаарлалт

Trigger ашиглахад дараах зүйлсийг мэдэх хэрэгтэй:

Recursive trigger: Trigger дотроос тухайн хүснэгтийг өөрчилбөл дахин trigger дуудагдаж давталтад орж болно — анхаарах хэрэгтэй.

Transaction: Trigger нь trigger дуудсан transaction-тай нэг бүлэгт ажилладаг. Trigger алдаа гаргавал бүх transaction ROLLBACK болно.

Хурдны нөлөө: Trigger нь нуугдмал байдлаар ажилладаг тул debug хийхэд хэцүү, performance-д нөлөөлдөг. Энгийн логикийг аппликейшн давхаргад байлгах нь дээр.

Хязгаарлалт:

  • Trigger дотроос CALL procedure() дуудаж болдог
  • Trigger дотроос COMMIT / ROLLBACK хийх боломжгүй
  • Нэг хүснэгтэд нэг төрлийн trigger нэг л байж болно (жишээ: AFTER INSERT ганцхан байна)

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

Хэрэглэгч ба эрх — MySQL-д хэрэглэгч үүсгэх, тодорхой эрх олгох, аюулгүй байдлыг хангах аргыг үзнэ.