iT邦幫忙

2022 iThome 鐵人賽

1
自我挑戰組

資料庫新手入門--以PostgreSQL為例系列 第 24

Day 24 妥妥的才算交易

  • 分享至 

  • xImage
  •  

媽媽砸摳,接著到雜貨店購買麥香奶茶,這也是許多人兒時記憶當中純粹的幸福,不過如果你付了十元,雜貨店卻不給你麥香奶茶,絕對氣炸! 得到這個教訓以後,以後購買麥香奶茶的時候你都會設法獲得保障,避免悲劇再發生,悟出人生的哲學 - 必需是妥妥的才算交易。

Database Transaction

資料庫交易就是要讓資料的變化過程妥妥的才可以,舉個萬年例子,假設有個應用是王大空轉帳給陳小明,我們在王大空的戶頭裡面扣了10,000元,但是發生停電中斷,這時候王大空戶頭被扣10,000元但是陳小明卻沒有收到這10,000元,這絕對是不可忍的,資料庫有個專門處理這種問題的功能就叫做交易,具備以下特點 :

  • 綑綁執行多個步驟或多個語句合併到一個操作中
  • 應該一起執行或根本不執行

1. 建立範例資料庫。

CREATE TABLE accounts (
	id SERIAL PRIMARY KEY,
	name VARCHAR(20) NOT NULL,
	balance INTEGER NOT NULL
)

2. 寫入資料,沒有使用交易的語法。(會遇到上述的問題)

INSERT INTO accounts (name, balance)
VALUES
	('王大空', 10000),
	('陳小明', -10000);

3. 使用交易的語法。

如果沒有完成寫入這兩筆資料,則會回到還沒發生寫入的時候。

// 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);

1. 交易開始

PostgreSQL 有三種可以宣告交易開始的語法。

// 語法1
BEGIN;

// 語法2
BEGIN WORK;

// 語法3
BEGIN TRANSACTION;

2. 插入資料

資料暫存於記憶體當中,不會立即寫入資料庫,如果這個時候開另外一個SESSION去看資料是不會看到這一筆資料的喔!

INSERT INTO customers(name, email)
VALUES('葛四俠','go4@test.com');

3. 插入一筆執行失敗的資料

這邊故意插入一筆有問題的資料,VALUES缺少了customer_id的資料,會造成寫入失敗。

INSERT INTO orders(name, amount_billed, customer_id)
VALUES('stojo泰坦杯', 880);

4. 有問題就滾回去

ROLLBACK就是告訴這個交易如果有問題就回到原點。(或設定的某個點,稍後會提及)

ROLLBACK;

5. 完成交易

完成交易也有三種寫法,一但SQL被執行到這邊的時候就代表交易成功了。(不過這個例子是失敗收場,只會執行到第4步就被ROLLBACK滾回去了)

// 語法1
COMMIT;

// 語法2
COMMIT WORK;

// 語法3
COMMIT TRANSACTION;

6. 看看

開啟新的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;

想滾回過去的某個時候(SAVEPOINT)

有些情況下,你可能會認為某些交易是可以接受退回到某個步驟就好,例如你覺得退回到寫完客戶資訊是可以接受的,那麼我們可以設置滾回點,當資料發生異常的時候的滾回去那個點。

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;

ACID

交易的四大特性 (誤人子弟版本)

  • 原子性 (Atomicity) : 妥妥的才算是交易完成,要就都執行完成,不然不想交易就不要交易。
  • 一致性 (Consistency) : 我拿到奶茶,你拿到10元,OK不虧。
  • 隔離性 (Isolation) : 交易完成之前,每個買家都應該要看到那個奶茶。
  • 永久性 (Durability) : 交易就此永久算數。

備註 : 請務必額外參考正經版本 Database Transaction & ACID


上一篇
Day 23 SQL條件判斷式
下一篇
Day 25 使用INDEX提升查詢速度
系列文
資料庫新手入門--以PostgreSQL為例30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言