从今天开始, 你是架构师,学会关键词就行,代码让AI实现😁
数据库就像持久化的 Excel,ORM 让你用代码操作它
今天你会学到这些关键词
| 关键词 | 一句话解释 | | :-- | :-- | | Drizzle ORM | TypeScript 友好的 ORM,用代码操作数据库 | | SQLite | 轻量级文件数据库,无需安装 | | Elysia | 高性能 Web 框架,链式 API 设计 | | 参数化查询 | 防止 SQL 注入的安全查询方式 |
一句话总结:用 Drizzle ORM + 参数化查询操作 SQLite,让 Elysia 服务拥有真正的数据持久化能力。
上节课回顾
上节课我们用 Elysia 实现了用户管理 API:
bash
GET /users → 查询所有用户
GET /users/:id → 查询单个用户
POST /users → 创建用户
PUT /users/:id → 更新用户
DELETE /users/:id → 删除用户
但数据存在内存里:
bash
const users = new Map();
问题:
-
• 服务重启,数据丢失
-
• 无法多服务共享数据
-
• 不能复杂查询
解决方案:使用数据库。
数据库是什么?
一句话:持久化存储数据的地方。
bash
内存存储(Map/数组) 数据库(SQLite/MySQL)
─────────────────────────────────────────────
• 服务重启数据丢失 • 数据持久保存
• 存在内存里 • 存在硬盘上
• 简单快速 • 功能强大,支持复杂查询
类比:
-
• 内存存储 = 草稿纸,写完就扔
-
• 数据库 = 笔记本,永久保存
为什么选择 SQLite 学习数据库?
SQLite 的适用场景:
| 场景 | 是否适合 SQLite | | :-- | :-- | | 学习数据库基础 | ✅ 完美 | | 开发测试环境 | ✅ 快速搭建 | | 小型应用(用户 < 10万) | ✅ 推荐 | | 独立桌面/移动应用 | ✅ 推荐 | | 高并发写入(> 1000 QPS) | ❌ 不推荐 | | 多进程同时写入 | ❌ 不推荐 | | 需要网络访问 | ❌ 不推荐 |
为什么用 SQLite 学习 SQL?
bash
传统数据库(MySQL/PostgreSQL) SQLite
─────────────────────────────────────────────
• 需要安装数据库服务 • 零配置,零安装
• 需要启动数据库服务 • 直接打开文件就能用
• 配置复杂(用户、权限、端口) • 就是一个 .db 文件
• 占用系统资源多 • 占用资源极少
• 命令行工具需要单独学习 • 直接用 AI 生成 SQL
SQLite 学习路线:
bash
第4课(SQLite)→ 理解数据库和 ORM 基础
↓
第8课(PostgreSQL)→ Docker 部署生产级数据库
↓
第15课(MySQL)→ Java Spring Boot 生产环境
一句话:先用 SQLite 快速入门,等项目大了再换 PostgreSQL。
SQL 是什么?
SQL 是操作数据库的语言。
bash
-- 查询所有用户
SELECT * FROM users;
-- 创建新用户
INSERT INTO users (name, email) VALUES ('张三', 'zs@example.com');
-- 更新用户
UPDATE users SET name = '李四' WHERE id = 1;
-- 删除用户
DELETE FROM users WHERE id = 1;
但我们不需要手写 SQL。
ORM 是什么?
ORM = 用代码操作数据库,不用写 SQL。
bash
// 不用写 SQL,用代码操作
await db.insert(users).values({ name: "张三", email: "zs@example.com" });
// 自动转成:INSERT INTO users (name, email) VALUES (?, ?)
好处:
-
• ✅ 不用记 SQL 语法
-
• ✅ 类型安全,IDE 有提示
-
• ✅ 代码更易维护
Drizzle ORM 简介
Drizzle 是一个轻量级、类型安全的 ORM,完美支持 Bun.js 和 Node.js。
安装:
bash
bun add drizzle-orm
bun add -d drizzle-kit
# Node.js 用户
npm install drizzle-orm
npm install -D drizzle-kit
用 AI 生成完整代码
复制这段提示词:
bash
用 Bun.js + Drizzle ORM + SQLite 创建用户管理系统
要求:
1. 数据库配置
- 使用 bun:sqlite(Bun 用户)或 better-sqlite3(Node.js 用户)
- 数据库文件 app.db
2. 用户表结构:
- id: 整数,自增主键
- name: 文本,必填
- email: 文本,必填,唯一
- createdAt: 时间戳,默认当前时间
3. 实现 RESTful API:
- GET /users - 查询所有用户
- GET /users/:id - 查询单个用户
- POST /users - 创建用户
- PUT /users/:id - 更新用户
- DELETE /users/:id - 删除用户
4. 安全要求:
- 所有 SQL 使用 :name 占位符
- 禁止字符串拼接 SQL
5. 统一响应格式:
{ success, data, message }
6. 使用 Elysia 框架
请生成完整的项目代码,包含:
- schema.ts - 表定义
- db.ts - 数据库连接
- index.ts - API 路由
AI 生成的代码结构
1. schema.ts - 定义表结构
bash
import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";
export const users = sqliteTable("users", {
id: integer("id").primaryKey({ autoIncrement: true }),
name: text("name").notNull(),
email: text("email").notNull().unique(),
createdAt: integer("created_at", { mode: "timestamp" })
.notNull()
.$defaultFn(() => new Date())
});
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
对应 SQL:
bash
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
created_at INTEGER NOT NULL
);
2. db.ts - 数据库连接
💡 Bun 用户 :使用
bun:sqlite💡 Node.js 用户 :使用better-sqlite3
bash
// Bun 用户
import { Database } from "bun:sqlite";
import { drizzle } from "drizzle-orm/bun-sqlite";
import * as schema from "./schema";
const sqlite = new Database("app.db");
export const db = drizzle(sqlite, { schema });
// 自动创建表
sqlite.run(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
created_at INTEGER NOT NULL DEFAULT (unixepoch())
)
`);
bash
// Node.js 用户
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite";
import * as schema from "./schema";
const sqlite = new Database("app.db");
export const db = drizzle(sqlite, { schema });
// 自动创建表
sqlite.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
created_at INTEGER NOT NULL DEFAULT (unixepoch())
)
`);
3. index.ts - API 实现
bash
import { eq } from "drizzle-orm";
import { Elysia } from "elysia";
import { db } from "./db";
import { users } from "./schema";
const app = new Elysia()
.onRequest(({ request }) => {
console.log(`${request.method} ${new URL(request.url).pathname}`);
})
// 查询所有用户
.get("/users", async () => {
const allUsers = await db.select().from(users).all();
return {
success: true,
data: allUsers,
message: "查询成功"
};
})
// 查询单个用户
.get("/users/:id", async ({ params: { id }, set }) => {
const user = await db.select().from(users).where(eq(users.id, Number(id))).get();
if (!user) {
set.status = 404;
return { success: false, data: null, message: "用户不存在" };
}
return {
success: true,
data: user,
message: "查询成功"
};
})
// 创建用户
.post("/users", async ({ body, set }) => {
const { name, email } = body as { name: string; email: string };
if (!name || !email) {
set.status = 400;
return { success: false, data: null, message: "name 和 email 不能为空" };
}
try {
const result = await db.insert(users).values({
name,
email
}).returning();
set.status = 201;
return {
success: true,
data: result[0],
message: "创建成功"
};
} catch (error) {
set.status = 400;
return { success: false, data: null, message: "邮箱已存在" };
}
})
// 更新用户
.put("/users/:id", async ({ params: { id }, body, set }) => {
const { name, email } = body as { name?: string; email?: string };
const result = await db.update(users)
.set({ name, email })
.where(eq(users.id, Number(id)))
.returning();
if (result.length === 0) {
set.status = 404;
return { success: false, data: null, message: "用户不存在" };
}
return {
success: true,
data: result[0],
message: "更新成功"
};
})
// 删除用户
.delete("/users/:id", async ({ params: { id }, set }) => {
const result = await db.delete(users).where(eq(users.id, Number(id))).returning();
if (result.length === 0) {
set.status = 404;
return { success: false, data: null, message: "用户不存在" };
}
return {
success: true,
data: null,
message: "删除成功"
};
})
.listen(3000);
console.log(`Server running at http://localhost:${app.server?.port}`);
💡 Node.js 用户注意:需要使用 Node 适配器
bashimport { Elysia } from "elysia"; import { node } from "@elysiajs/node"; // ... 路由代码 ... .listen(3000, node); // ← 加上 node 适配器
运行测试
安装依赖:
bash
bun install
# Node.js 用户
npm install
启动服务:
bash
bun run index.ts
# Node.js 用户
npm run dev
测试接口:
bash
# 创建用户
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name": "张三", "email": "zs@example.com"}'
# 查询所有用户
curl http://localhost:3000/users
# 服务重启后,数据还在!
核心概念对照
| 概念 | Drizzle 代码 | 对应 SQL | | :-- | :-- | :-- | | 查询所有 | db.select().from(users) | SELECT * FROM users | | 条件查询 | .where(eq(users.id, id)) | WHERE id = ? | | 插入 | db.insert(users).values({...}) | INSERT INTO users ... | | 更新 | db.update(users).set({...}) | UPDATE users SET ... | | 删除 | db.delete(users) | DELETE FROM users |
安全提示:参数化查询
❌ 错误写法(SQL 注入风险):
bash
const sql = `SELECT * FROM users WHERE email = '${email}'`;
// 如果 email = "' OR '1'='1"
// 变成:SELECT * FROM users WHERE email = '' OR '1'='1'
// 结果:返回所有用户!
✅ 正确写法(Drizzle 自动参数化):
bash
await db.select().from(users).where(eq(users.email, email));
// 自动使用占位符,安全!
核心收获
今天学习了:
✅ 数据库 = 持久化存储✅ ORM = 用代码操作数据库✅ Drizzle = Bun.js/Node.js 的 ORM 选择✅ 参数化查询 = 防止 SQL 注入
下节课预告
第5课:登录功能怎么实现?一文搞懂认证
我们将:
-
• 理解认证的概念
-
• 学习 JWT 工作原理
-
• 实现注册登录功能
思考题:
如果要给文章表添加一个外键关联用户(作者),表结构应该怎么设计?
欢迎在评论区分享你的设计。
如果觉得有帮助,欢迎点赞、在看、转发。