前端转全栈 03:数据库与 SQL 入门——把数据真正存下来
系列目录:本文是「前端转全栈:Next.js + Supabase 实战」系列的第 3 篇。前两篇讲了心智模型和 HTTP,这一篇进入「存储」——数据库与 SQL。
很多前端同学把数据库想得特别玄乎。其实——数据库就是一个会听话的 Excel:有表格、有列、有行,你用一种叫 SQL 的语言命令它「把符合条件的行拿来」。
一、把数据库想成 Excel
| 概念 | Excel 类比 | 说明 |
|------|-----------|------|
| 数据库(Database) | 一个工作簿文件 | 比如本站的 postgres 库 |
| 表(Table) | 一张工作表 | comments、views 各是一张表 |
| 字段/列(Column) | 表头的一列 | content、created_at |
| 记录/行(Row) | 表格里的一行 | 一条具体评论 |
| 主键(Primary Key) | 行号且唯一 | 每条记录的唯一身份证 |
二、本站真实的建表语句
看本站 supabase/schema.sql 里 comments 表的定义:
CREATE TABLE IF NOT EXISTS comments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
post_slug TEXT NOT NULL,
author_name TEXT NOT NULL,
author_avatar TEXT,
content TEXT NOT NULL,
user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
逐列拆解:
id UUID PRIMARY KEY DEFAULT gen_random_uuid():主键,自动生成唯一 UUID。post_slug TEXT NOT NULL:NOT NULL表示必填,不填数据库直接报错。author_avatar TEXT:没有NOT NULL,表示可空。user_id UUID REFERENCES auth.users(id):外键,指向 Supabase 自带的用户表,表示「这条评论属于哪个用户」。created_at TIMESTAMPTZ DEFAULT now():默认取当前时间。
TIMESTAMPTZ是「带时区的时间戳」,存 UTC。千万别用裸TIMESTAMP,否则跨时区会乱。
三、关系:为什么需要外键
一个博客有「文章」和「评论」,评论必须属于某篇文章——这就是一对多关系。
posts (1) ────< comments (多)
│
└── user_id 指向 users (1)
外键(REFERENCES)保证数据不「悬空」:你不能插入一条 user_id 不存在的评论。这就是数据库的约束力,比你在代码里写 if 判断可靠得多。
ON DELETE SET NULL 表示:如果用户被删了,评论的 user_id 置空但评论保留——这是一种业务取舍。
四、SQL 四大操作:增删改查(CRUD)
查(Read)—— 你最常用的
-- 查某篇文章的所有评论,按时间倒序
SELECT * FROM comments
WHERE post_slug = 'frontend-fullstack-01-mindset'
ORDER BY created_at DESC;
对应到本站 route.ts 的 GET:
const { data } = await supabase
.from("comments")
.select("*")
.eq("post_slug", postSlug)
.order("created_at", { ascending: false })
看到没?Supabase 的查询语法就是 SQL 的「链式翻译」,底层还是这条 SQL。
增(Create)
INSERT INTO comments (post_slug, content, author_name, user_id)
VALUES ('xxx', '很棒', '小明', 'uuid-here');
改(Update)
UPDATE comments SET content = '修改后的内容'
WHERE id = 'uuid-here';
删(Delete)
DELETE FROM comments WHERE id = 'uuid-here';
⚠️
UPDATE/DELETE永远记得带WHERE,否则会改/删全表。这是新手最惨的事故之一,生产环境尤甚。
五、索引:让查询快 100 倍
WHERE post_slug = ... 这种查询,如果表很大,数据库得逐行扫。给常用查询列加索引:
CREATE INDEX IF NOT EXISTS idx_comments_post_slug
ON comments (post_slug);
索引就像书的目录——查某章直接翻到,而不是从头读。但索引会拖慢写入、占空间,只为高频查询列建。
六、前端视角的三个提醒
- 永远别在前端拼 SQL。前端只能发请求,SQL 在服务端 / 数据库层执行。谁在前端写 SQL 谁就是安全漏洞制造机。
- 数据库是真相来源。缓存、前端状态都可能错,数据库里的才是准的。
- 用 Supabase 不用自己装数据库。站点后台直接开 SQL Editor 把
schema.sql粘进去执行即可建好表,零运维。
总结
- 数据库 ≈ 会听话的 Excel:表、列、行、主键。
- 外键保证关系不悬空;
NOT NULL/ 默认值约束数据质量。 - CRUD = SELECT / INSERT / UPDATE / DELETE,UPDATE/DELETE 必带 WHERE。
- 索引加速查询,但按需建。
- 本站的
supabase/schema.sql就是你最好的建表范本。
下一篇,我们把「前端(Next.js)」和「服务端」打通——Next.js 服务端:Server/Client Components 与 Route Handlers。
练习:在 Supabase SQL Editor 里执行
schema.sql建好表,然后手动插一条评论,再用SELECT * FROM comments;查出来,感受「数据真的落库了」。
Comments
Sign in to leave a comment.