暴露只读视图
视图是数据库中的预定义查询,对外表现为一张虚拟表。当需要对外提供只读的复杂查询结果(多表 JOIN、聚合、数据脱敏)时,视图比直接暴露表更安全、更可控。本教程带你完成从创建视图到发布 API 的完整流程。
场景
图书管理系统需要提供一个只读接口,返回每本书的详细信息,包括书名、作者名、分类名和出版社——这些数据分散在四张表中。直接暴露表意味着消费者需要自己做四次查询和关联。我们用一个视图来封装这个查询。
第一步:创建视图
在数据库中创建视图,将需要的字段 JOIN 在一起:
sql
CREATE VIEW dbo.vw_Books_Details AS
SELECT
b.id,
b.title,
b.[year],
b.pages,
a.name AS author_name,
c.name AS category_name,
p.name AS publisher_name
FROM dbo.Books b
LEFT JOIN dbo.Authors a ON b.author_id = a.id
LEFT JOIN dbo.Categories c ON b.category_id = c.id
LEFT JOIN dbo.Publishers p ON b.publisher_id = p.id;视图已经包含了业务需要的全部字段。现在把它暴露为 API。
第二步:添加视图实体
bash
dab add BookDetail \
--source "dbo.vw_Books_Details" \
--source.type "view" \
--fields.name "id" \
--fields.primary-key "true" \
--permissions "anonymous:read"关键点:
--source.type "view":声明这是一个视图,不是表。--fields.primary-key "true":视图书没有物理主键,必须手动指定。
生成的配置:
json
{
"BookDetail": {
"source": {
"type": "view",
"object": "dbo.vw_Books_Details"
},
"fields": [
{ "name": "id", "primary-key": true }
],
"permissions": [
{ "role": "anonymous", "actions": ["read"] }
]
}
}WARNING
如果不指定 primary-key,按主键查询(GET /api/BookDetail/id/1)会退化为列表查询并返回空数组。视图没有物理主键,引擎无法自动推断。
第三步:仅授予只读权限
视图书是只读的(包含多表 JOIN),只需授予 read 权限:
json
{
"permissions": [
{ "role": "anonymous", "actions": ["read"] }
]
}不要给视图配置 create、update、delete 权限——即使配置了,大多数多表 JOIN 视图也是不可更新的,数据库会拒绝写操作。
第四步:启动并测试
bash
dab start查询全部
bash
curl http://localhost:5000/api/BookDetailjson
{
"value": [
{
"id": 1000,
"title": "深入浅出 SQL Server",
"year": 2020,
"pages": 326,
"author_name": "张三",
"category_name": "数据库",
"publisher_name": "科技出版社"
}
]
}按主键查询
bash
curl http://localhost:5000/api/BookDetail/id/1000筛选和排序
bash
# 某个分类下的书,按年份降序
curl "http://localhost:5000/api/BookDetail?\$filter=category_name%20eq%20%27数据库%27&\$orderby=year%20desc"
# 只返回标题和作者
curl "http://localhost:5000/api/BookDetail?\$select=title,author_name"GraphQL 查询
graphql
{
bookDetails(
filter: { category_name: { eq: "数据库" } }
orderBy: { year: DESC }
) {
items { title author_name year pages }
}
}视图 vs 直接暴露表
| 维度 | 视图 | 直接暴露表 |
|---|---|---|
| 数据来源 | 可跨多表 JOIN | 单表 |
| 字段控制 | 视图定义时就限定 | 通过 fields.exclude 排除 |
| 业务逻辑 | 在 SQL 中封装 | 无 |
| 只读安全 | SQL 层面不可更新 | 需要权限配置控制 |
| 维护 | 改 SQL 即可,无需改 DAB 配置 | 需同时改配置 |
对于以下场景,优先用视图:
- 跨多表的数据查询需要对外提供。
- 需要对原始数据做计算、聚合或脱敏。
- 不希望消费者接触到原始表结构。
- 只读数据查询,不需要写操作。
限制
- 视图不支持
relationships配置(不能在视图上定义 GraphQL 关系查询)。 - 存储过程不能作为视图的替代——视图支持筛选、排序、分页,存储过程不支持。
- 如果视图可更新(基于单表的简单视图),可以授予写权限,但需要逐一验证数据库是否允许更新操作。
下一步
- 从数据库表生成 API — 表实体的完整配置流程。
- 调用存储过程 — 封装复杂业务逻辑。
