cover

概念概覽

flowchart LR
    C[Create 新增] -->|POST| C1[INSERT INTO]
    R[Read 讀取] -->|GET| R1[SELECT]
    U[Update 更新] -->|PUT / PATCH| U1[UPDATE]
    D[Delete 刪除] -->|DELETE| D1[DELETE FROM]

    C1 --> DB[(資料庫)]
    R1 --> DB
    U1 --> DB
    D1 --> DB

什麼是 CRUD?

不管你做的是社群平台、電商網站、還是一個簡單的待辦清單 App,背後都離不開四件事:新增資料、讀取資料、更新資料、刪除資料。這就是 CRUD。聽起來簡單?確實,但它就像料理的「煎煮炒炸」——所有複雜的應用,拆到最底層都是這四個動作的組合。

CRUD 是四個英文單字的縮寫,代表對資料的四種基本操作:

操作英文說明SQLHTTP Method
新增Create建立新資料INSERTPOST
讀取Read查詢資料SELECTGET
更新Update修改資料UPDATEPUT/PATCH
刪除Delete移除資料DELETEDELETE

CRUD 與 RESTful API

為什麼要特別提 HTTP 方法?因為當你的前端需要跟後端溝通時,CRUD 的每一個操作都有一個「約定俗成」的 HTTP Method 與之對應。這個對應關係搞清楚了,你讀任何 API 文件都會非常順暢。

在設計 RESTful API 時,CRUD 操作直接對應到 HTTP 方法:

// 使用者資源的 CRUD API 範例
 
// Create - 新增使用者
POST /api/users
Body: { "name": "John", "email": "john@example.com" }
 
// Read - 取得所有使用者
GET /api/users
 
// Read - 取得單一使用者
GET /api/users/123
 
// Update - 更新使用者資料
PUT /api/users/123
Body: { "name": "John Doe", "email": "john.doe@example.com" }
 
// Delete - 刪除使用者
DELETE /api/users/123

資料庫 CRUD 操作

SQL 範例

-- Create: 新增資料
INSERT INTO users (name, email, created_at)
VALUES ('John', 'john@example.com', NOW());
 
-- Read: 查詢資料
SELECT * FROM users WHERE id = 1;
SELECT * FROM users WHERE email LIKE '%@example.com';
 
-- Update: 更新資料
UPDATE users
SET name = 'John Doe', updated_at = NOW()
WHERE id = 1;
 
-- Delete: 刪除資料
DELETE FROM users WHERE id = 1;

ORM 範例(使用 Prisma)

// Create
const user = await prisma.user.create({
  data: {
    name: 'John',
    email: 'john@example.com',
  },
});
 
// Read
const user = await prisma.user.findUnique({
  where: { id: 1 },
});
 
const users = await prisma.user.findMany({
  where: { email: { contains: '@example.com' } },
});
 
// Update
const updatedUser = await prisma.user.update({
  where: { id: 1 },
  data: { name: 'John Doe' },
});
 
// Delete
const deletedUser = await prisma.user.delete({
  where: { id: 1 },
});

軟刪除 vs 硬刪除

硬刪除(Hard Delete)

直接從資料庫移除資料,資料無法復原。

DELETE FROM users WHERE id = 1;

軟刪除(Soft Delete)

保留資料但標記為已刪除狀態,資料可以復原。

-- 軟刪除
UPDATE users
SET deleted_at = NOW(), is_deleted = true
WHERE id = 1;
 
-- 查詢時排除已刪除的資料
SELECT * FROM users WHERE is_deleted = false;
 
-- 復原資料
UPDATE users
SET deleted_at = NULL, is_deleted = false
WHERE id = 1;

在商業應用中,軟刪除通常是更好的選擇,原因包括:

  • 資料可追溯和復原
  • 符合法規要求(如 GDPR 的資料保留期限)
  • 避免關聯資料完整性問題

CRUD 最佳實踐

1. 資料驗證

在執行 CRUD 操作前,務必驗證輸入資料。

// 使用 Zod 進行資料驗證
import { z } from 'zod';
 
const userSchema = z.object({
  name: z.string().min(2).max(50),
  email: z.string().email(),
});
 
// 驗證後再進行 Create
const validatedData = userSchema.parse(inputData);
await prisma.user.create({ data: validatedData });

2. 權限控制

確保使用者只能操作有權限的資料。

// 確認使用者有權限更新此資源
const post = await prisma.post.findUnique({ where: { id: postId } });
 
if (post.authorId !== currentUser.id) {
  throw new Error('Unauthorized');
}
 
await prisma.post.update({
  where: { id: postId },
  data: updateData,
});

3. 交易處理

多個 CRUD 操作需要保證原子性時使用交易。

await prisma.$transaction(async (tx) => {
  // 扣除帳戶餘額
  await tx.account.update({
    where: { id: fromAccountId },
    data: { balance: { decrement: amount } },
  });
 
  // 增加目標帳戶餘額
  await tx.account.update({
    where: { id: toAccountId },
    data: { balance: { increment: amount } },
  });
});

CRUD 與其他概念的關係

  • CRUD 是對資料操作的描述,著重於「做什麼」
  • RESTful API 是 API 設計風格,定義「如何做」
  • HTTP Methods 是傳輸協定的動詞,是「怎麼傳輸」

三者是不同層面的概念,但在實務上緊密結合。


延伸閱讀

RESTful API 設計最佳實踐 RESTful API API 概念 資料庫基礎