Transaction
Transaction нь олон SQL үйлдлийг нэг бүлэг болгон гүйцэтгэдэг — бүгд амжилттай болно, эсвэл бүгд цуцлагдана. Банкны шилжүүлэг, захиалга зэрэг алдаа зөвшөөрөхгүй үйлдэлд зайлшгүй шаардлагатай.
Яагаад transaction хэрэгтэй вэ?
-- Transaction үгүй: аюултай!
UPDATE accounts SET balance = balance - 50000 WHERE id = 1; -- Болдын данс
-- ← Яг энд серверийн алдаа гарлаа!
UPDATE accounts SET balance = balance + 50000 WHERE id = 2; -- Оюуны данс
-- Үр дүн: Болдын данснаас мөнгө гарсан, Оюуны данс нэмэгдээгүй
Transaction ашиглавал бүгд хамт амжиж, эсвэл хамт цуцлагдана.
BEGIN / COMMIT / ROLLBACK
-- Transaction эхлүүлэх
START TRANSACTION;
-- эсвэл:
BEGIN;
UPDATE accounts SET balance = balance - 50000 WHERE id = 1;
UPDATE accounts SET balance = balance + 50000 WHERE id = 2;
-- Бүх зүйл зөв болсон бол хадгалах
COMMIT;
START TRANSACTION;
UPDATE accounts SET balance = balance - 50000 WHERE id = 1;
UPDATE accounts SET balance = balance + 50000 WHERE id = 2;
-- Алдаа гарсан тул бүгдийг цуцлах
ROLLBACK;
-- Хоёр UPDATE аль аль нь буцаагдана
ACID шинж чанар
Transaction нь дараах 4 шинж чанарыг баталгаажуулдаг:
| Үсэг | Нэр | Утга | | ----- | ------------------------------ | ------------------------------------------- | | A | Atomicity (Бүтнэ чанар) | Бүх үйлдэл биелнэ, эсвэл нэг ч биелэхгүй | | C | Consistency (Нийцэл) | Өгөгдлийн сан дүрмийг зөрчихгүй | | I | Isolation (Тусгаарлалт) | Зэрэгцээ transaction бие биедээ нөлөөлөхгүй | | D | Durability (Тогтвортой байдал) | COMMIT хийсэн өгөгдөл алдагдахгүй |
SAVEPOINT — завсрын цэг
Transaction дотор завсрын цэг тавьж, зөвхөн тухайн цэг хүртэл буцаах боломжтой:
START TRANSACTION;
INSERT INTO orders (customer, amount) VALUES ('Болд', 15000);
SAVEPOINT after_order; -- завсрын цэг
INSERT INTO order_items (order_id, product_id) VALUES (LAST_INSERT_ID(), 5);
SAVEPOINT after_items;
UPDATE inventory SET stock = stock - 1 WHERE product_id = 5;
-- Inventory алдаа гарлаа!
ROLLBACK TO SAVEPOINT after_items; -- зөвхөн inventory-г буцаах
-- order болон order_items хэвээр байна
-- Гараар зассаны дараа:
UPDATE inventory SET stock = stock - 1 WHERE product_id = 5;
COMMIT;
-- SAVEPOINT устгах
RELEASE SAVEPOINT after_order;
Stored procedure дотор transaction
DELIMITER //
CREATE PROCEDURE TransferMoney(
IN from_id INT,
IN to_id INT,
IN amount DECIMAL(10,2),
OUT result VARCHAR(100)
)
BEGIN
DECLARE v_balance DECIMAL(10,2);
-- Алдааг барьж авах (MySQL error handler)
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET result = 'Алдаа гарлаа — transaction цуцлагдлаа';
END;
START TRANSACTION;
-- Үлдэгдэл шалгах
SELECT balance INTO v_balance FROM accounts WHERE id = from_id FOR UPDATE;
IF v_balance < amount THEN
ROLLBACK;
SET result = 'Үлдэгдэл хүрэлцэхгүй';
ELSE
UPDATE accounts SET balance = balance - amount WHERE id = from_id;
UPDATE accounts SET balance = balance + amount WHERE id = to_id;
COMMIT;
SET result = 'Шилжүүлэг амжилттай';
END IF;
END //
DELIMITER ;
CALL TransferMoney(1, 2, 50000, @res);
SELECT @res;
FOR UPDATE нь transaction дуусах хүртэл тухайн мөрийг lock хийнэ — өөр transaction зэрэгцэн өөрчлөхөөс хамгаална.
AUTO_COMMIT
MySQL нь анхдагчаар AUTO_COMMIT = 1 — мэдэгдэл болгон автоматаар COMMIT хийнэ:
-- Одоогийн AUTO_COMMIT тохиргоо
SELECT @@autocommit;
-- AUTO_COMMIT унтраах
SET autocommit = 0;
-- Одоо COMMIT хийх хүртэл өөрчлөлт хадгалагдахгүй
-- Буцаах
SET autocommit = 1;
START TRANSACTION ашиглавал AUTO_COMMIT тохиргооноос үл хамааран тухайн transaction-д хяналт авна.
InnoDB vs MyISAM
MySQL-д хүснэгтийн storage engine нь transaction дэмжих эсэхийг тодорхойлно:
| | InnoDB | MyISAM | | -------------- | --------------- | ------------------- | | Transaction | ✓ Дэмждэг | ✗ Дэмждэггүй | | Foreign key | ✓ Дэмждэг | ✗ Дэмждэггүй | | Row-level lock | ✓ Мөрийн түгжээ | ✗ Хүснэгтийн түгжээ | | Crash recovery | ✓ Байдаг | ✗ Байхгүй | | Хурд (read) | Хурдан | Арай хурдан |
MySQL 5.5-аас хойш InnoDB нь анхдагч engine тул ихэнх тохиолдолд тусгайлан тохируулах шаардлагагүй.
-- Хүснэгтийн engine шалгах
SHOW TABLE STATUS WHERE Name = 'orders';
-- Engine өөрчлөх (анхаар: том хүснэгтэд удаан!)
ALTER TABLE old_table ENGINE = InnoDB;
Дараагийн хичээлд:
Trigger — хүснэгтийн өөрчлөлтөд автоматаар ажилладаг тусгай procedure, audit log хэрхэн бичих аргыг үзнэ.