# 概念 (/docs/cloud/services/database/concepts)



库是隔离单元，表定义记录的结构，字段定义值的类型，行保存实际记录。

## 库、表、字段、行 [#库表字段行]

API Key 决定你能访问哪些库。表和字段可用 ID 或名称寻址；关联字段使用表 ID，因此改名不会改变关联目标。库的标签用于分类和筛选。

默认行只包含主键 `id` 和用户字段，`select=*`、`return=representation` 及 RPC 都遵循这一规则。字段保留名只有 `id`；新字段不能以 `_` 开头。`created_at`、`updated_at`、`version` 可作为普通字段。字段名以小写字母开头，后续只含小写字母、数字和下划线，最多 63 字；表名也允许下划线开头。已有下划线用户字段仍可读写，且优先于同名系统元数据；这时该表无法访问同名元数据。

系统元数据只读，需显式取用：`select=*,_version,_created_at,_updated_at`。`*` 不会展开它们。可用 `_version=eq.3` 过滤，或 `order=_created_at.desc` 排序。不指定 `order` 时，仍按内部创建时间再按 `id` 排序。过滤或排序使用旧元数据名且没有同名用户字段时返回 400：`details` 为 `use _created_at`（或对应的新名字），`hint` 为 `system metadata moved to underscore columns`。

时间字段可定义为 `{"name":"created_at","type":"datetime","default":"now()"}`。插入时省略该字段，就保存服务器当前 UTC 时间；读回字段定义仍显示 `"now()"`。显式 null 和 PATCH 中省略的字段不使用默认值。string/json 字段的 `"now()"` 默认值仍为字面量字符串。给已有表新增这个字段时，回填也会求值。

## 七种字段类型 [#七种字段类型]

| 类型         | 保存的值                                                                                                                                         |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `string`   | 字符串                                                                                                                                          |
| `integer`  | 整数                                                                                                                                           |
| `number`   | 数值                                                                                                                                           |
| `boolean`  | `true` 或 `false`                                                                                                                             |
| `datetime` | RFC 3339 日期时间，例如 `2026-10-11T08:30:00+08:00`；不存在的日期（如 2 月 30 日）返回 400。值统一按 UTC、3 位毫秒保存和读出，例如 `2026-10-11T00:30:00.000Z`；精度为毫秒，超过 3 位的小数秒四舍五入 |
| `json`     | 满足指定 JSON Schema 的 JSON 值                                                                                                                    |
| `link`     | 同一库中另一张表的行 ID，或多个行 ID                                                                                                                        |

`required` 要求写入非空值。新增带 `default` 的字段时，已有行一律用它回填；不带 `default` 的新字段在已有行上为空。在已有行的表上新增 `required` 字段时必须提供 `default`；把已有字段改为 `required` 时，若仍有行在该列为空则返回 400 `VALIDATION_FAILED` 并说明空行数，先补齐这些行再修改。`unique` 要求值唯一。前五种类型默认建立索引；不需要的字段可以设 `indexed: false`。`json` 和 `link` 不能设为索引字段。字段类型创建后不可修改。

## 批量写入与事务 [#批量写入与事务]

一次 POST 最多插入 **500 行**。单次请求是原子的：任何一行失败，整批回滚。跨请求没有事务；需要一起成功的行应放在一次批量 POST 中。有关联依赖时先查询目标，再插入引用它的行；先查后插不能保证并发期间目标不变，仍需处理插入时的关联错误。

同一批次会按所有行的键的并集补齐缺失值为 `null`（PostgREST 行为），因此某行省略必填字段可能导致整批失败。发送 `Prefer: missing=default` 可让缺失的键使用字段默认值；显式传入的 `null` 仍为 `null`，没有默认值的必填字段仍必须提供。

默认 `return=minimal`：成功返回 201，body 为空。需要读回新增行时发送 `Prefer: return=representation`，或在 supabase-js 的 `.insert(...)` 后调用 `.select()`。

## JSON Schema [#json-schema]

`json` 字段必须在 `options.schema` 中提供 JSON Schema。例如，下面的字段只接受包含字符串 `summary` 的对象。

```json
{
  "name": "detail",
  "type": "json",
  "options": {
    "schema": {
      "type": "object",
      "properties": { "summary": { "type": "string" } },
      "required": ["summary"],
      "additionalProperties": false
    }
  }
}
```

更新 schema 约束之后的写入，不会重写已有行。查询时可用 `detail->>summary` 读取字符串值。

## 关联与删除保护 [#关联与删除保护]

`link` 的 `options.linked_table_id` 指向同一库中的目标表，`multiple` 决定保存单个行 ID 还是行 ID 数组。关联目标创建后不可更改。

```json
{
  "name": "project",
  "type": "link",
  "options": { "linked_table_id": "tbl_example", "multiple": false }
}
```

把 `tbl_example` 换成已创建表的 ID。引用不存在的行会被拒绝；删除仍被其它行引用的行也会被拒绝；同一次删除中的行互相引用时可以一起删除。先解除引用，再删除目标，不会自动级联删除。

## 用 \_version 避免覆盖他人的更新 [#用-_version-避免覆盖他人的更新]

新行的 `_version` 为 1，每次更新递增。更新时同时过滤行 ID 和读到的版本；没有返回行表示该条件不再匹配，需要重新读取后决定下一步。

```typescript
const { data: row, error: readError } = await supabase.from("tasks")
  .select("*,_version").eq("id", rowId).single();
if (readError) throw readError;

const { data, error } = await supabase.from("tasks")
  .update({ done: true })
  .eq("id", row.id)
  .eq("_version", row._version)
  .select();
if (error) throw error;
if (data.length === 0) throw new Error("Read the row again before updating");
```

## 删除库后 7 天内恢复 [#删除库后-7-天内恢复]

删除库后不能再读写其中的行。在 7 天内调用[恢复库](/docs/api/native/database/databases#恢复库)可以重新使用库及保留的表和行；超过窗口无法恢复。此恢复能力针对整个库，不是单独删除的表、字段或行。

[API 参考 →](/docs/api/native/database) · [限制与错误 →](/docs/cloud/services/database/limits-and-errors)
