WeHelp
PostgreSQL 是一套免費、開源的強大物件關聯式資料庫管理系統,適合處理複雜的結構化資料與高負載應用程式。
  1. PostgreSQL 下載安裝
  2. 啟動、連線測試
  3. Database 管理
  4. Schema 管理
  5. SQL 資料表管理
  6. SQL 資料管理
  7. SQL 資料取得、篩選
  8. 欄位的資料型態
  9. 資料交易簡介、操作
  10. 使用者管理
  11. Python 程式連線
  12. Node.js 程式連線
  13. C# 程式連線
資料交易簡介、操作
# PostgreSQL Transaction(交易)簡介 Transaction 是一組被視為「單一工作單位」的資料庫操作。這些操作要嘛全部成功,要嘛全部取消,避免資料只更新一半而造成不一致。 例如:銀行轉帳需要同時完成: 1. 從帳戶 A 扣款 2. 將款項存入帳戶 B 如果扣款成功但存款失敗,就會造成資料錯誤,因此應將兩個操作放在同一個 Transaction 中。 --- ## 一、Transaction 的 ACID 特性 PostgreSQL 的 Transaction 具備 ACID 特性: ### 1. Atomicity(原子性) 交易中的所有操作視為一個整體: - 全部成功:`COMMIT` - 任一操作失敗:`ROLLBACK` ### 2. Consistency(一致性) 交易完成後,資料必須符合資料表的約束,例如: - `PRIMARY KEY` - `FOREIGN KEY` - `UNIQUE` - `CHECK` - `NOT NULL` ### 3. Isolation(隔離性) 同時執行的交易彼此隔離,避免讀取到不一致的資料。 ### 4. Durability(持久性) 交易一旦 `COMMIT`,即使資料庫重新啟動,已提交的資料仍應保留。 --- # 二、基本 Transaction 操作 PostgreSQL 常用的交易控制指令如下: ```sql BEGIN; -- 或 START TRANSACTION; ``` 開始交易。 ```sql COMMIT; ``` 提交交易,永久保存變更。 ```sql ROLLBACK; ``` 取消交易,還原尚未提交的變更。 --- ## 三、基本範例 假設有銀行帳戶資料表: ```sql CREATE TABLE accounts ( account_id integer PRIMARY KEY, owner_name text NOT NULL, balance numeric(12, 2) NOT NULL ); ``` 執行轉帳: ```sql BEGIN; UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1; UPDATE accounts SET balance = balance + 1000 WHERE account_id = 2; COMMIT; ``` 上述兩個 `UPDATE` 都成功後,執行 `COMMIT`,交易才會正式完成。 如果中途發生錯誤,可以取消: ```sql BEGIN; UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1; -- 假設後續操作發生錯誤 ROLLBACK; ``` 執行 `ROLLBACK` 後,前面的扣款也會被還原。 --- # 四、檢查操作結果後再提交 實務上通常會檢查更新筆數或餘額是否足夠。 例如: ```sql BEGIN; UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1 AND balance >= 1000; -- 如果沒有更新任何資料,代表帳戶不存在或餘額不足 -- 此時應執行: ROLLBACK; ``` 如果條件符合,再繼續: ```sql UPDATE accounts SET balance = balance + 1000 WHERE account_id = 2; COMMIT; ``` 在應用程式中,通常會由程式檢查每個 SQL 的執行結果,決定要 `COMMIT` 或 `ROLLBACK`。 --- # 五、Savepoint(儲存點) 如果不想直接取消整個 Transaction,可以使用 `SAVEPOINT`,只回復到某一個階段。 ```sql BEGIN; INSERT INTO users (user_id, username) VALUES (1, 'alice'); SAVEPOINT before_second_insert; INSERT INTO users (user_id, username) VALUES (2, 'bob'); -- 只回復第二個 INSERT ROLLBACK TO SAVEPOINT before_second_insert; -- 第一個 INSERT 仍然保留 COMMIT; ``` 相關指令: ```sql SAVEPOINT savepoint_name; ``` 建立儲存點。 ```sql ROLLBACK TO SAVEPOINT savepoint_name; ``` 回復到指定儲存點,但不結束整個 Transaction。 ```sql RELEASE SAVEPOINT savepoint_name; ``` 刪除儲存點。 --- # 六、交易隔離層級 PostgreSQL 支援以下交易隔離層級: ```sql READ COMMITTED REPEATABLE READ SERIALIZABLE ``` 可以在交易開始時指定: ```sql BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ``` 或: ```sql SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; ``` ## 1. READ COMMITTED PostgreSQL 預設層級。 ```sql BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED; ``` 特性: - 每個 SQL 指令看到的是該指令開始時已提交的資料 - 同一個 Transaction 中,不同 SQL 可能看到不同版本的資料 - 適合一般 CRUD 操作 ## 2. REPEATABLE READ ```sql BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; ``` 特性: - 同一個 Transaction 內,多次讀取通常會看到一致的資料快照 - 可避免 Non-repeatable Read - 可能因為並行交易而發生序列化錯誤,需要重新執行交易 ## 3. SERIALIZABLE ```sql BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; ``` 特性: - 最嚴格的隔離層級 - 效果如同交易依序執行 - 並行衝突時可能產生錯誤,應由應用程式重試 --- # 七、鎖定資料列 如果需要確保某筆資料在交易期間不被其他交易修改,可以使用: ```sql BEGIN; SELECT * FROM accounts WHERE account_id = 1 FOR UPDATE; ``` `FOR UPDATE` 會鎖定查詢到的資料列,其他交易若也要修改或使用相同鎖定,通常需要等待。 常見用途: - 扣款 - 庫存更新 - 預約名額 - 搶票 - 避免同一筆資料被同時修改 例如庫存扣除: ```sql BEGIN; SELECT stock FROM products WHERE product_id = 10 FOR UPDATE; UPDATE products SET stock = stock - 1 WHERE product_id = 10 AND stock > 0; COMMIT; ``` --- # 八、Autocommit(自動提交) 在許多工具或 PostgreSQL 用戶端中,預設會啟用 Auto-commit。 例如直接執行: ```sql INSERT INTO users (user_id, username) VALUES (1, 'alice'); ``` 如果 Auto-commit 開啟,這個 `INSERT` 通常會立即自動提交,相當於: ```sql BEGIN; INSERT INTO users (user_id, username) VALUES (1, 'alice'); COMMIT; ``` 如果要將多個 SQL 放在同一筆交易中,必須明確使用: ```sql BEGIN; -- 多個 SQL 操作 COMMIT; ``` 在 `psql` 中,也可以使用: ```sql \set AUTOCOMMIT off ``` 關閉自動提交。 --- # 九、錯誤發生後的處理 PostgreSQL 中,如果 Transaction 內的某個 SQL 發生錯誤,該 Transaction 通常會進入失敗狀態。 例如: ```sql BEGIN; INSERT INTO users (user_id, username) VALUES (1, 'alice'); -- 假設這裡發生 PRIMARY KEY 衝突 INSERT INTO users (user_id, username) VALUES (1, 'bob'); -- 後續 SQL 通常會出現: -- current transaction is aborted ROLLBACK; ``` 發生錯誤後,通常必須先執行: ```sql ROLLBACK; ``` 之後才能開始新的交易。 若使用 `SAVEPOINT`,則可以只回復部分操作: ```sql BEGIN; INSERT INTO users (user_id, username) VALUES (1, 'alice'); SAVEPOINT sp1; -- 可能失敗的操作 INSERT INTO users (user_id, username) VALUES (1, 'bob'); ROLLBACK TO SAVEPOINT sp1; COMMIT; ``` --- # 十、在應用程式中使用 Transaction 以 Python、Java、Node.js 等程式語言操作 PostgreSQL 時,通常流程如下: ```text 建立資料庫連線 ↓ BEGIN ↓ 執行多個 SQL ↓ 全部成功? ├─ 是 → COMMIT └─ 否 → ROLLBACK ``` 伪程式碼如下: ```python try: connection.begin() execute("UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1") execute("UPDATE accounts SET balance = balance + 1000 WHERE account_id = 2") connection.commit() except Exception: connection.rollback() raise ``` 使用連線池時,`COMMIT` 或 `ROLLBACK` 後,才應將連線歸還給連線池,避免未完成的交易影響下一個使用者。 --- # 十一、常見注意事項 ## 1. Transaction 不要開太久 長時間未提交的交易可能: - 持有資料列鎖 - 阻塞其他交易 - 造成資料庫膨脹 - 影響 Vacuum - 增加死結機率 因此應盡量縮短交易範圍。 ## 2. 注意 Deadlock(死結) 例如: - Transaction A 先鎖定資料列 1,再等待資料列 2 - Transaction B 先鎖定資料列 2,再等待資料列 1 PostgreSQL 會偵測死結並中止其中一個交易。應用程式通常需要捕捉錯誤並重新嘗試。 ## 3. Transaction 結束時要明確處理 每次使用 Transaction 後,都要確保執行: ```sql COMMIT; ``` 或: ```sql ROLLBACK; ``` 避免連線長期處於未完成交易狀態。 --- ## 總結 PostgreSQL 的 Transaction 主要透過以下指令控制: ```sql BEGIN; -- 執行一組 SQL 操作 COMMIT; ``` 若操作失敗,則使用: ```sql ROLLBACK; ``` 常見使用原則是: 1. 將必須同時成功的操作放在同一個 Transaction 中 2. 全部成功才 `COMMIT` 3. 發生錯誤就 `ROLLBACK` 4. 需要部分回復時使用 `SAVEPOINT` 5. 依需求選擇交易隔離層級 6. 盡量縮短交易時間,避免鎖定與死結問題
相關學習地圖、教學課程
Python 資料工程
從 0 開始,成為資料工程師的學習路徑。