媽媽砸摳,接著到雜貨店購買麥香奶茶,這也是許多人兒時記憶當中純粹的幸福,不過如果你付了十元,雜貨店卻不給你麥香奶茶,絕對氣炸! 得到這個教訓以後,以後購買麥香奶茶的時候你都會設法獲得保障,避免悲劇再發生,悟出人生的哲學 - 必需是妥妥的才算交易。
資料庫交易就是要讓資料的變化過程妥妥的才可以,舉個萬年例子,假設有個應用是王大空轉帳給陳小明,我們在王大空的戶頭裡面扣了10,000元,但是發生停電中斷,這時候王大空戶頭被扣10,000元但是陳小明卻沒有收到這10,000元,這絕對是不可忍的,資料庫有個專門處理這種問題的功能就叫做交易,具備以下特點 :
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
name VARCHAR(20) NOT NULL,
balance INTEGER NOT NULL
)
INSERT INTO accounts (name, balance)
VALUES
('王大空', 10000),
('陳小明', -10000);
如果沒有完成寫入這兩筆資料,則會回到還沒發生寫入的時候。
// 1. 開始交易 (以下操作直到COMMIT都視為同一個綑綁的操作)
BEGIN;
// 寫入資料
INSERT INTO accounts (name, balance)
VALUES
('王大空', 10000),
('陳小明', -10000);
// 2. 有問題就滾回去
ROLLBACK;
// 3. 交易成功
COMMIT;
清槍開始,清槍蹲下。
CREATE TABLE customers(
id SERIAL PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(200)
);
CREATE TABLE orders(
id SERIAL PRIMARY KEY,
name VARCHAR(255),
amount_billed INT,
customer_id INT REFERENCES customers
);
INSERT INTO customers(name, email)
VALUES('王大空', 'wangtakung@test.com'),
('劉小賢', 'liuhsiaohsien@test.com'),
('翟大傑', 'chaitachieh@test.com');
INSERT INTO orders(name, amount_billed, customer_id)
VALUES('樂扣樂扣隨行杯', 799, 1),
('象印不銹鋼真空保威杯', 890, 2),
('虎牌碳酸抗菌型保冷瓶', 1290, 1),
('天氣吸杯', 1280, 3);
PostgreSQL 有三種可以宣告交易開始的語法。
// 語法1
BEGIN;
// 語法2
BEGIN WORK;
// 語法3
BEGIN TRANSACTION;
資料暫存於記憶體當中,不會立即寫入資料庫,如果這個時候開另外一個SESSION去看資料是不會看到這一筆資料的喔!
INSERT INTO customers(name, email)
VALUES('葛四俠','go4@test.com');
這邊故意插入一筆有問題的資料,VALUES缺少了customer_id的資料,會造成寫入失敗。
INSERT INTO orders(name, amount_billed, customer_id)
VALUES('stojo泰坦杯', 880);
ROLLBACK就是告訴這個交易如果有問題就回到原點。(或設定的某個點,稍後會提及)
ROLLBACK;
完成交易也有三種寫法,一但SQL被執行到這邊的時候就代表交易成功了。(不過這個例子是失敗收場,只會執行到第4步就被ROLLBACK滾回去了)
// 語法1
COMMIT;
// 語法2
COMMIT WORK;
// 語法3
COMMIT TRANSACTION;
開啟新的SESSION可以看到所寫入的值。
SELECT * FROM customers;
這次我們讓資料寫對,就能執行到COMMIT,完成交易。
BEGIN
INSERT INTO customers(name, email)
VALUES('葛四俠','go4@test.com')
INSERT INTO orders(name, amount_billed, customer_id)
VALUES('stojo泰坦杯', 880, 4)
ROLLBACK
COMMIT;
有些情況下,你可能會認為某些交易是可以接受退回到某個步驟就好,例如你覺得退回到寫完客戶資訊是可以接受的,那麼我們可以設置滾回點,當資料發生異常的時候的滾回去那個點。
BEGIN
INSERT INTO customers(name, email)
VALUES('葛四俠','go4@test.com')
// 設置滾回點
SAVEPOINT save_customers
INSERT INTO orders(name, amount_billed, customer_id)
VALUES('stojo泰坦杯', 880, 4)
// 滾回那個滾回點
ROLLBACK TO SAVEPOINT save_customers
COMMIT;
交易的四大特性 (誤人子弟版本)
備註 : 請務必額外參考正經版本 Database Transaction & ACID