Python DB-API
Python DB-API(PEP 249)是 Python 存取關聯式資料庫的共通介面標準,sqlite3、psycopg、PyMySQL、mysql-connector-python 都遵循它。因此只要學會「連線 → cursor → execute → fetch → commit → close」這套流程,換資料庫時程式幾乎不用改,只需要換驅動與連線參數。
標準流程
import sqlite3 # 換成 psycopg、pymysql 等驅動,流程相同
conn = sqlite3.connect("example.db") # 1. 建立連線
cur = conn.cursor() # 2. 取得 cursor
cur.execute("SELECT name, age FROM users WHERE age > ?", (20,)) # 3. 執行 SQL
rows = cur.fetchall() # 4. 取得結果
cur.execute("INSERT INTO users (name, age) VALUES (?, ?)", ("Eve", 22))
conn.commit() # 5. 寫入後提交交易
cur.close() # 6. 關閉 cursor 與連線
conn.close()
| 物件/方法 | 作用 |
|---|---|
connect() |
建立連線,參數依驅動而異 |
cursor() |
建立游標,用來執行 SQL 與讀取結果 |
execute(sql, params) |
執行一條 SQL,params 為 tuple 或 dict |
executemany(sql, seq) |
以多組參數重複執行,常用於批次新增 |
fetchone() / fetchmany(n) / fetchall() |
取一筆/取 n 筆/取全部 |
commit() / rollback() |
提交/取消目前交易 |
rowcount / lastrowid |
受影響筆數/最後新增的 id |
參數化查詢與 SQL 注入
SQL 注入(SQL Injection)是最常見的資料庫安全漏洞:程式把使用者輸入直接拼進 SQL 字串,攻擊者就能輸入特殊字元竄改 SQL 的意思。
name = "x' OR '1'='1"
# ❌ 危險:字串拼接,WHERE 條件變成永遠成立,會撈出所有資料
cur.execute(f"SELECT * FROM users WHERE name = '{name}'")
# ✅ 安全:參數化查詢,驅動會把 name 當成「值」而不是 SQL
cur.execute("SELECT * FROM users WHERE name = ?", (name,))
各驅動的佔位符(paramstyle)不同,這是換資料庫時最常需要修改的地方:
| 驅動 | 佔位符 | 範例 |
|---|---|---|
sqlite3 |
? 或 :name |
WHERE id = ? |
psycopg / psycopg2 |
%s 或 %(name)s |
WHERE id = %s |
PyMySQL / mysql-connector-python |
%s 或 %(name)s |
WHERE id = %s |
佔位符只能代表「值」
資料表名稱、欄位名稱、ORDER BY 方向等 SQL 結構不能用佔位符。若必須動態指定,請用白名單檢查(例如 if column not in {"name", "age"}: raise ValueError),或改用 SQLAlchemy 組查詢。
交易:commit 與 rollback
DB-API 預設在第一條修改資料的 SQL 執行時自動開始交易,直到呼叫 commit() 才會真正寫入。發生錯誤時應呼叫 rollback() 取消整組操作,保持資料一致:
try:
cur.execute("UPDATE accounts SET balance = balance - ? WHERE id = ?", (100, 1))
cur.execute("UPDATE accounts SET balance = balance + ? WHERE id = ?", (100, 2))
conn.commit()
except Exception:
conn.rollback()
raise
多數驅動的連線物件支援 with conn:,效果等同上面的 try/commit/rollback(各驅動是否同時關閉連線略有不同,請參考各資料庫頁面)。
不要把密碼寫死在程式裡
連線資訊建議放在環境變數或 .env 檔,並將 .env 加入 .gitignore,避免密碼被推上 GitHub:
import os
import psycopg
conn = psycopg.connect(os.environ["DATABASE_URL"])
# DATABASE_URL 例如:postgresql://app_user:app_password@localhost:5432/app_db
搭配 pandas 做資料分析
pandas 可以把查詢結果直接讀成 DataFrame,也能把 DataFrame 寫回資料表。SQLite 可直接傳入連線物件;其他資料庫建議傳入 SQLAlchemy 的 engine:
import sqlite3
import pandas as pd
with sqlite3.connect("example.db") as conn:
df = pd.read_sql("SELECT * FROM users WHERE age > ?", conn, params=(20,))
print(df.describe())
df.to_sql("users_backup", conn, if_exists="replace", index=False)
推薦影音
Python Tutorial: Psycopg2 for Beginners(Ferds the NetDev)
簡述:示範用 psycopg2 連線 PostgreSQL、建立 cursor、執行參數化查詢與提交交易,流程與本頁介紹的 DB-API 標準流程一致,換成其他驅動也適用。