什麼是 ORM?應用程式如何與資料庫溝通,簡單解說
ORM(物件關聯映射器,object-relational mapper)是位於應用程式與關聯式資料庫之間的一個程式庫。開發者不必用 SQL 寫資料庫查詢,而是以程式語言中的普通物件處理資料,例如 db.booking.create(...) 或 Booking.find(...)。ORM 會把這些操作翻譯成 SQL、執行,再把結果轉回物件。常見例子有 TypeScript 的 Prisma 和 Drizzle、Python 的 SQLAlchemy,以及 C# 的 Entity Framework Core。
用 AI 做 App 時,ORM 為何重要
當 AI 應用程式生成工具為你的 App 加入資料庫時,通常也會加入一個 ORM 來連接它。你不必親手寫 ORM 程式碼,但知道它的存在會有幫助:
- 資料模型放在程式碼裡。 ORM 的 schema 檔案往往是描述 App 資料最清楚的文件:有哪些資料表、每個資料表有哪些欄位,以及它們如何相連。閱讀它,就能快速檢查 AI 是否正確理解你的需求。
- 資料庫的改動要經過遷移。 當你要求「在客戶資料加入電話號碼」,AI 會更新模型並建立一個遷移。明白這點,就知道為何某些改動要先套用,功能才會在正式環境生效。
- 預設更安全。 ORM 建立查詢的方式能防範 SQL 注入攻擊,這是手動組裝查詢的 App 最常見的安全漏洞之一。
- 效能陷阱。 ORM 很容易讓你不經意地執行數百個細小查詢,而其實一個就夠。這是 AI 生成的 App 頁面變慢的常見原因之一。
日常比喻
想像一位英國遊客和一位日本店主,兩人語言不通,要靠翻譯員溝通。
遊客(你的 App)說:「我想要你們最便宜的三款茶。」翻譯員(ORM)把它譯成準確的日文(SQL),交給店主(資料庫),再把答案譯回英文。
遊客不必學懂日文,大部分對話都沒問題。但遇上複雜的商議,直接用對方的語言溝通會更好,所以大多數 ORM 都讓開發者在有需要時直接寫原生 SQL。
ORM 如何運作
Postgres 等資料庫把資料存放在由行和列組成的資料表中,並以 SQL 查詢。程式語言則處理物件:例如一個有 date、customer 和 status 的預約。ORM 負責在兩者之間對應:
| 資料庫端 | ORM/程式碼端 |
|---|---|
資料表 bookings | 模型 Booking |
| 資料列(row) | 一個預約物件 |
欄位 starts_at | 屬性 startsAt |
外來鍵 customer_id | 關聯 booking.customer |
SELECT、INSERT、UPDATE、DELETE | find、create、update、delete 方法 |
這四種操作,就是幾乎所有 App 都建基於的 CRUD 動作。
實例:用 Prisma 處理預約
以下是一個簡化的 Prisma schema,用於美容院預約 App。它描述了兩張資料表及它們的關聯:
model Customer {
id Int @id @default(autoincrement())
name String
email String @unique
bookings Booking[]
}
model Booking {
id Int @id @default(autoincrement())
startsAt DateTime
service String
customer Customer @relation(fields: [customerId], references: [id])
customerId Int
}
簡單來說:一位客戶有名字、獨一無二的電郵,以及多個預約;每個預約有開始時間和服務項目,並屬於一位客戶。
現在 App 需要「Lena 即將到來的預約,由最近的排序」:
const bookings = await db.booking.findMany({
where: {
customer: { email: "lena@example.com" },
startsAt: { gte: new Date() },
},
orderBy: { startsAt: "asc" },
});
ORM 會把它轉成大致如下的 SQL,執行後返回一串預約物件:
SELECT b.* FROM "Booking" b
JOIN "Customer" c ON c.id = b."customerId"
WHERE c.email = $1 AND b."startsAt" >= $2
ORDER BY b."startsAt" ASC;
$1 和 $2 是佔位符:電郵和日期會與查詢文字分開傳送,這正是防止 SQL 注入的做法。
遷移
如果你接著要求「讓客戶可以新增電話號碼」,AI 會在 Customer 模型中加入 phone String?(? 表示可選填),並生成一個遷移,即一段類似 ALTER TABLE "Customer" ADD COLUMN "phone" TEXT; 的小型 SQL 腳本。遷移會按次序保存,因此每個資料庫副本都可以調整至相同結構,改動紀錄也會保留。
各語言常用的 ORM
| 語言 | 常用 ORM |
|---|---|
| TypeScript / JavaScript | Prisma、Drizzle、TypeORM、Sequelize |
| Python | SQLAlchemy、Django ORM、SQLModel |
| C# | Entity Framework Core |
| Java | Hibernate(常見於 Spring Data JPA) |
| Ruby | Active Record |
ORM 隱藏 SQL 的程度各有不同。Prisma 使用自家的 schema 語言和查詢寫法;Drizzle 則刻意貼近 SQL 的結構,同時保持完整的型別。較輕量的工具稱為查詢建構器(query builder),例如 TypeScript 的 Knex 或 Kysely,它們協助在程式中建立 SQL,但不會把資料列映射成完整物件。
重要詞彙
| 詞彙 | 意思 |
|---|---|
| 模型(Model) | 資料表及其欄位的程式碼定義。 |
| Schema | 所有資料表、欄位及關聯的完整描述。 |
| 關聯(Relation) | 模型之間的連結,例如預約屬於某位客戶。 |
| 遷移(Migration) | 有版本編號、用來改變資料庫結構的腳本。 |
| 查詢建構器(Query builder) | 較輕量的工具,在程式中建立 SQL,但不做完整的物件映射。 |
| N+1 問題 | 先執行一個查詢取得列表,再為每個項目各執行一次查詢,規模一大就會變慢。 |
| 原生 SQL(Raw SQL) | 手寫的 SQL,在 ORM 礙事時使用。 |
常見誤解
- 「ORM 就是資料庫。」 不是。它是翻譯員,你仍然需要 Postgres 之類的資料庫。
- 「用了 ORM,就不必了解自己的資料。」 資料表設計不良,經過 ORM 一樣令人頭痛。良好的資料模型比工具更重要。
- 「ORM 一定很慢。」 日常查詢通常沒問題。變慢多數是因為 N+1 查詢或缺少索引之類的模式,而這些都可以修正。
- 「用了 ORM 就完全沒有 SQL 注入風險。」 標準的 ORM 方法是安全的,但如果把使用者輸入直接貼進原生 SQL,仍然危險。
- 「修改 schema 檔案就會改動正式資料庫。」 只有在建立遷移並套用到該資料庫之後才會。
可以問你的 AI 生成工具的問題
- 「展示資料庫 schema,並用淺白的語言解釋每張資料表及其關聯。」
- 「這個專案用了哪個 ORM?遷移檔案放在哪裡?」
- 「改動任何資料表之前,請先告訴我現有資料會否受影響;有數據的欄位未經我同意,絕不可刪除。」
- 「檢查最慢的頁面有否 N+1 查詢,並在列表被篩選或排序的地方加入索引。」
- 「確保每個使用使用者輸入的查詢都經過 ORM 或使用參數,不要用字串拼湊 SQL。」
Mythex 中的 ORM
當你的 App 需要儲存資料,Mythex 會為專案加入一個專用的 Postgres 資料庫(在聊天中提出要求,或使用 /database 指令),並把連線資料注入工作區及已發布的 App(資料庫說明)。之後,代理程式會撰寫讀取及儲存資料的程式碼。如果你有偏好,例如「用 Prisma」、「用 SQLAlchemy」或「純 SQL,不用 ORM」,請在聊天中說明。隨時可以要求它逐步講解 schema;你也可以在程式碼編輯器中閱讀檔案。如需更全面的了解,請參閱什麼是資料庫及 SQL 與 NoSQL 比較。
常見問題
簡單來說,什麼是 ORM?
ORM(物件關聯映射器,object-relational mapper)是一個程式庫,位於應用程式與關聯式資料庫之間。它讓開發者以程式語言中的普通物件讀取和儲存資料,並在背後替他們編寫 SQL 查詢。
ORM 有哪些例子?
常見的 ORM 包括 TypeScript 和 JavaScript 的 Prisma 與 Drizzle、Python 的 SQLAlchemy 及 Django ORM、C# 的 Entity Framework Core、Java 的 Hibernate,以及 Ruby on Rails 的 Active Record。
ORM 比手寫 SQL 好嗎?
視乎工作性質而定。ORM 令日常的讀寫更快寫、更安全、更易修改;而手寫 SQL 則能完全掌控複雜報表或對效能要求高的查詢。大多數 ORM 都容許你在有需要時直接改用原生 SQL。
什麼是遷移(migration)?
遷移是一段細小、有版本編號的腳本,用來改變資料庫的結構,例如新增一張資料表或一個欄位。ORM 可以根據你的資料模型生成遷移,確保每個資料庫副本(在手提電腦、測試環境及正式環境)都有相同結構。