Kodokon kodokon.com

ทรานแซกชัน: BEGIN, COMMIT, ROLLBACK และ ACID

ทำให้การเขียนข้อมูลของคุณเป็นอะตอมด้วยทรานแซกชัน และเข้าใจว่าการรับประกัน ACID มีความหมายอย่างไรในการใช้งานประจำวัน

8 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

การโอนเงินธนาคารคือ UPDATE สองครั้ง: หักเงินจากบัญชีหนึ่ง และเพิ่มเงินให้อีกบัญชีหนึ่ง หากครั้งที่สองล้มเหลว ฐานข้อมูลก็จะโกหก ทรานแซกชัน ทำให้บล็อกนี้แบ่งแยกไม่ได้ พร้อมการรับประกัน ACID ได้แก่ Atomicity (ความเป็นอะตอม คือทำทั้งหมดหรือไม่ทำเลย), Consistency (ความคงเส้นคงวา คือข้อกำหนดยังคงถูกต้อง), Isolation (การแยกตัว คือทรานแซกชันที่ทำพร้อมกันจะไม่มีวันเห็นสภาวะที่อีกฝ่ายทำค้างไว้ครึ่งทาง), Durability (ความคงทน คือ COMMIT จะอยู่รอดแม้ระบบล่ม) สำหรับบทเรียนนี้ ควรใช้ไคลเอนต์ sqlite3 ตัวจริง เพราะแซนด์บ็อกซ์บนเว็บบางตัวจะ auto-commit ทุกคิวรี

SQL
CREATE TABLE accounts (
  id INTEGER PRIMARY KEY,
  owner TEXT NOT NULL,
  balance REAL NOT NULL CHECK (balance >= 0)
);

INSERT INTO accounts (owner, balance)
VALUES
  ('alice', 500.0),
  ('bruno', 120.0);
ข้อกำหนด CHECK ห้ามไม่ให้ยอดคงเหลือติดลบ

กรณีปกติ: BEGIN เปิดทรานแซกชัน การเขียนต่าง ๆ ทยอยสะสมกันไป แล้ว COMMIT ทำให้ทั้งหมดเป็นผลสุดท้ายพร้อมกันในคราวเดียว ในระหว่างนั้น ไม่มีการเชื่อมต่ออื่นใดเห็นสถานะกลาง (alice ถูกหักเงินแล้ว แต่ bruno ยังไม่ได้รับเงิน)

SQL
BEGIN;

UPDATE accounts
SET balance = balance - 200
WHERE owner = 'alice';

UPDATE accounts
SET balance = balance + 200
WHERE owner = 'bruno';

COMMIT;

SELECT owner, balance FROM accounts;
การโอนแบบอะตอม: 300 สำหรับ alice, 320 สำหรับ bruno

ตอนนี้มาดูกรณีล้มเหลว การหักเงิน bruno ไป 400 จะละเมิด CHECK (balance >= 0) คำสั่งจึงล้มเหลว มีข้อละเอียดอ่อนของ SQLite คือ โดยค่าเริ่มต้น ข้อผิดพลาดจะยกเลิก คำสั่งที่ผิดพลาด แต่ปล่อยให้ทรานแซกชัน ยังเปิดอยู่ ขึ้นอยู่กับโค้ดแอปพลิเคชันของคุณที่จะตัดสินใจ: ROLLBACK เพื่อย้อนกลับทุกอย่าง (ปฏิกิริยาที่สมเหตุสมผล) หรือทำต่อไปหากข้อผิดพลาดนั้นแก้ไขได้

SQL
BEGIN;

UPDATE accounts
SET balance = balance - 400
WHERE owner = 'bruno';
-- Error: CHECK (balance >= 0) rejects the row.

ROLLBACK;

SELECT owner, balance FROM accounts;
หลัง ROLLBACK ยอดคงเหลือจาก COMMIT ครั้งล่าสุดยังคงอยู่ครบถ้วน

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. ความเป็นอะตอม ซึ่งเป็นตัว A ใน ACID รับประกันอะไร?
    • คิวรีในทรานแซกชันทำงานเร็วขึ้น
    • ทรานแซกชันมีผลทั้งหมดหรือไม่มีผลเลย
    • ทรานแซกชันสองตัวไม่มีทางอ่านตารางเดียวกันได้
  2. หลัง ROLLBACK ฐานข้อมูลอยู่ในสถานะใด?
    • สถานะของ COMMIT ครั้งล่าสุด ราวกับว่า BEGIN ไม่เคยเกิดขึ้น
    • UPDATE ที่สำเร็จก่อนเกิดข้อผิดพลาดจะถูกเก็บไว้
    • ฐานข้อมูลจะยังคงถูกล็อกจนกว่าจะถึง BEGIN ครั้งถัดไป
  3. ทำไม INSERT 10,000 ครั้งจึงเร็วกว่ามากเมื่ออยู่ในทรานแซกชัน SQLite เดียว?
    • SQLite บีบอัดข้อมูลที่แทรกเข้าไปเป็นชุดใหญ่
    • ซิงก์ลงดิสก์เพียงครั้งเดียวตอน COMMIT แทนที่จะเป็นครั้งละคำสั่ง
    • ดัชนีถูกปิดใช้งานระหว่างทรานแซกชัน