ทำความเข้าใจโมเดลการล็อกของ SQLite ทรานแซกชันของมัน และความผิดปกติด้านการแยกกันที่มาตรฐาน SQL อธิบายไว้
เปิดบทเรียนนี้ใน KodokonSQLite ล็อกที่ระดับ ไฟล์ฐานข้อมูลทั้งไฟล์ ไม่ใช่ที่ระดับแถว ในโหมดเริ่มต้น (rollback journal) ผู้อ่านจะใช้ล็อก SHARED ร่วมกัน แต่ผู้เขียนได้เพียงรายเดียวในแต่ละครั้งที่จะได้ล็อก EXCLUSIVE ผลที่ตามมาคือ: การเขียนถูก ทำให้เป็นลำดับ (serialized) มาสร้างตารางเพื่อทดลองใช้ทรานแซกชันกัน
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
balance INTEGER NOT NULL
);
INSERT INTO accounts (id, balance)
VALUES (1, 100), (2, 50);
-- Read: deferred transaction (default)
BEGIN;
SELECT balance FROM accounts WHERE id = 1;
COMMIT;ล็อกวิวัฒน์ไปเป็นขั้น ๆ: UNLOCKED จากนั้น SHARED (อ่าน), RESERVED (ตั้งใจจะเขียน), PENDING และสุดท้าย EXCLUSIVE (เขียน) หากทรานแซกชันหนึ่งถือล็อกสำหรับเขียนอยู่แล้ว อีกทรานแซกชันจะได้รับข้อผิดพลาด SQLITE_BUSY แทนที่จะล้มเหลวทันที ให้ตั้งค่าหน่วงเวลารอด้วย busy_timeout และเปิดใช้งานโหมด WAL เพื่อให้ผู้อ่านและผู้เขียนดำเนินการไปพร้อมกันได้
-- A single writer, concurrent readers
PRAGMA journal_mode = WAL;
-- Wait up to 5 s if the database is busy
PRAGMA busy_timeout = 5000;มาตรฐาน SQL อธิบายความผิดปกติไว้สามอย่าง: การอ่านข้อมูลสกปรก (dirty read) (การอ่านข้อมูลที่ยังไม่ได้คอมมิต), การอ่านที่ทำซ้ำไม่ได้ (non-repeatable read) (การอ่านแถวเดิมซ้ำแล้วเห็นค่าที่ต่างออกไป) และ การอ่านภาพหลอน (phantom read) (การรันการสืบค้นแบบช่วงซ้ำแล้วเห็นแถวใหม่ ๆ ปรากฏขึ้น) เนื่องจาก SQLite ทำให้ผู้เขียนเป็นลำดับ มันจึงมีพฤติกรรมเสมือนเป็น SERIALIZABLE: ความผิดปกติเหล่านี้จะไม่ปรากฏ (ยกเว้นในโหมด shared-cache ที่ใช้ read_uncommitted) ในที่อื่น ๆ คุณเลือกระดับได้อย่างชัดแจ้ง
-- Atomic transfer: immediate write lock
BEGIN IMMEDIATE;
UPDATE accounts
SET balance = balance - 10
WHERE id = 1;
UPDATE accounts
SET balance = balance + 10
WHERE id = 2;
COMMIT;BEGIN และ BEGIN IMMEDIATE?