ทำให้การเขียนข้อมูลของคุณเป็นอะตอมด้วยทรานแซกชัน และเข้าใจว่าการรับประกัน ACID มีความหมายอย่างไรในการใช้งานประจำวัน
เปิดบทเรียนนี้ใน Kodokonการโอนเงินธนาคารคือ UPDATE สองครั้ง: หักเงินจากบัญชีหนึ่ง และเพิ่มเงินให้อีกบัญชีหนึ่ง หากครั้งที่สองล้มเหลว ฐานข้อมูลก็จะโกหก ทรานแซกชัน ทำให้บล็อกนี้แบ่งแยกไม่ได้ พร้อมการรับประกัน ACID ได้แก่ Atomicity (ความเป็นอะตอม คือทำทั้งหมดหรือไม่ทำเลย), Consistency (ความคงเส้นคงวา คือข้อกำหนดยังคงถูกต้อง), Isolation (การแยกตัว คือทรานแซกชันที่ทำพร้อมกันจะไม่มีวันเห็นสภาวะที่อีกฝ่ายทำค้างไว้ครึ่งทาง), Durability (ความคงทน คือ COMMIT จะอยู่รอดแม้ระบบล่ม) สำหรับบทเรียนนี้ ควรใช้ไคลเอนต์ sqlite3 ตัวจริง เพราะแซนด์บ็อกซ์บนเว็บบางตัวจะ auto-commit ทุกคิวรี
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);กรณีปกติ: BEGIN เปิดทรานแซกชัน การเขียนต่าง ๆ ทยอยสะสมกันไป แล้ว COMMIT ทำให้ทั้งหมดเป็นผลสุดท้ายพร้อมกันในคราวเดียว ในระหว่างนั้น ไม่มีการเชื่อมต่ออื่นใดเห็นสถานะกลาง (alice ถูกหักเงินแล้ว แต่ bruno ยังไม่ได้รับเงิน)
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;ตอนนี้มาดูกรณีล้มเหลว การหักเงิน bruno ไป 400 จะละเมิด CHECK (balance >= 0) คำสั่งจึงล้มเหลว มีข้อละเอียดอ่อนของ SQLite คือ โดยค่าเริ่มต้น ข้อผิดพลาดจะยกเลิก คำสั่งที่ผิดพลาด แต่ปล่อยให้ทรานแซกชัน ยังเปิดอยู่ ขึ้นอยู่กับโค้ดแอปพลิเคชันของคุณที่จะตัดสินใจ: ROLLBACK เพื่อย้อนกลับทุกอย่าง (ปฏิกิริยาที่สมเหตุสมผล) หรือทำต่อไปหากข้อผิดพลาดนั้นแก้ไขได้
BEGIN;
UPDATE accounts
SET balance = balance - 400
WHERE owner = 'bruno';
-- Error: CHECK (balance >= 0) rejects the row.
ROLLBACK;
SELECT owner, balance FROM accounts;