SQL vs SQL Builder vs ORM
與關聯式資料庫對話:SQL vs SQL Builder vs ORM
前言
開發網站無可避免的會和關聯式資料庫打交道,而互動的方式有三種:
- SQL
- SQL Builder
- Object-Relational Mapping (ORM)
這三者有著不同的使用方式、優缺點與適用場景,了解它們的差異能幫助我們做出更適合專案需求的技術選擇。
SQL
SQL 是與關聯式資料庫溝通的語言,雖然不同資料庫常見語法上有些許差異,但彼此間差異不大。想要獲得最好的彈性與效能可以使用 SQL,極大的彈性也可能暗藏 SQL Injection 風險。
// ❌ 用戶可能添加惡意輸入造成拼湊出惡意的 SQL 指令
const username = req.body.username;const password = req.body.password;
const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
db.query(query, (err, results) => { if (results.length > 0) { // 登入成功 } else { // 登入失敗 }});
// ✅ 透過 Prepared Statement 安全處理用戶輸入防止 SQL injectionconst username = req.body.username;const password = req.body.password;
const query = 'SELECT * FROM users WHERE username = ? AND password = ?';
db.query(query, [username, password], (err, results) => { // 安全地處理查詢});
SQL Builder
介於靈活性與安全性之間的方案,透過抽象函式組合,以程式碼的方式構建 SQL,進而迴避 SQL Injection 問題。
// Drizzle ORMimport { eq, and } from 'drizzle-orm';import { db } from './db';import { users } from './schema';
const username = req.body.username;const password = req.body.password;
const result = await db .select() .from(users) .where(and( eq(users.username, username), eq(users.password, password) ));
if (result.length > 0) { // 登入成功} else { // 登入失敗}
ORM
提供一種將資料表對映成程式中的 Class、資料列對應成物件 Object 的方式。通常 ORM 也會處理不同 DB 之間的差異、SQL Injection 問題。
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
const username = req.body.username;const password = req.body.password;
const user = await prisma.user.findFirst({ where: { username, password, },});
if (user) { // 登入成功} else { // 登入失敗}
我的學習經驗
在 Node.js 生態系中我使用 MySQL2 與本地資料庫溝通,但 SQL 返回的資料沒有 TypeScript 型別是一大問題,這個問題通常透過 ORM 框架透過定義好的 Schema 來生成 TypeScript 型別。
發現 ORM 之間的經歷轉移麻煩且上手難度高,既要理解 ORM 的抽象,又要在必要時能理解其背後的 SQL 會是很頭疼的問題,因此我會選擇盡可能少量抽象的 SQL Builder 來熟悉 SQL 語法,同時享受它帶來的便利,在 TS 生態系裡面推薦 Drizzle ORM 有很完善的 SQL Builder ~ ORM 體驗。
總結
特性 | SQL | SQL Builder | ORM |
---|---|---|---|
操作彈性 | 高 | 中 | 低 |
學習門檻 | 低 | 中 | 中 |
安全性 | 低(自行防範) | 高 | 高 |
效能掌控 | 最高 | 高 | 中 |
適合場景 | 著重效能 | 通用 | 增刪查改為主 |