SpacetimeDB 数据库模块完全指南:Module 与 Database 的核心区别及 spacetime CLI 全生命周期管理
【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB
SpacetimeDB 的模块(Module)与数据库(Database)是一对极易混淆但至关重要的概念:模块是你编写的代码(表结构与服务端逻辑),而数据库是该模块真正运行起来、承载实际数据与客户端连接的实例。本文以官方核心概念文档为主线,结合本仓库的 CLI 源码实现,系统讲解两者区别、模块构成、支持的语言生态、数据库命名规则,以及使用spacetimeCLI 完成创建、更新、删除、查询、日志与列表管理的完整实操。
什么是 Module(模块)
Module(模块)是「代码」这一层抽象:它是函数与 schema(表结构)定义的集合,可以用 TypeScript、C#、Rust 或 C++ 编写。模块定义了数据库的结构,以及负责处理和响应客户端请求的服务端逻辑。通俗地说,模块就是你的业务程序本身。
Module 与 Database 的区别
理解二者区别是整个 SpacetimeDB 使用模型的基石:
- Module 是你写的代码。它定义了 schema(表)与业务逻辑(reducers、procedures、views)。模块需要被编译并发布(deploy)到 SpacetimeDB 上。Rust、C#、C++ 模块会编译为 WebAssembly(Wasm),而 TypeScript 模块运行在 V8 引擎上。
- Database 是模块的"运行实例"。它拥有模块的 schema 与逻辑,外加真实存储的数据。
两者关系可以类比为「类与对象」或「程序与进程」:同一份模块代码,可以发布到多个数据库——例如分别用于测试、预发(staging)、生产环境,每个数据库各自拥有独立的数据。
关于重发布(republish)的重要事实:当你更新模块代码并重新发布时,SpacetimeDB 会更新数据库的 schema 与逻辑,已有数据会保留。不过对于复杂 schema 变更,你需要谨慎处理迁移(migration),因为并非所有改动都能自动完成——详见后文「自动迁移」相关章节。
从源码结构看,数据库的删除与发布请求都直接作用于数据库的 identity,例如 publish.rs 中以PUT /v1/database/{domain}创建或更新数据库、以POST /v1/database匿名创建,这印证了「数据库是可寻址的运行实体」这一设计。
Module 里有什么
一个模块包含以下组成部分:
- Tables(表)—— 定义数据结构与存储。
- Reducers(归约器)—— 以事务方式修改数据的服务端函数。
- Procedures(过程)—— 可以执行外部操作(如 HTTP 请求)并返回结果的函数。
- Views(视图)—— 基于数据之上的只读计算查询。
模块的服务端逻辑正是由这三类函数承载:reducers(事务性状态变更)、procedures(具备外部能力的函数)、views(只读查询)。
支持的模块语言
SpacetimeDB 模块可以用多种语言编写,均获得完整支持:
| 语言 | 适用场景 | 运行载体 | 快速入门 |
|---|---|---|---|
| TypeScript | 熟悉 JavaScript/Node.js 的开发者 | V8 引擎 | TypeScript 快速入门 |
| C# | 使用 Unity 或 .NET 的开发者 | WebAssembly(默认),亦支持 NativeAOT-LLVM 实验编译 | C# 快速入门 |
| Rust | 追求高性能的开发者 | WebAssembly | Rust 快速入门 |
| C++ | Unreal Engine 或 C++ 生态开发者 | WebAssembly | C++ 快速入门 |
需要说明的是,C++ 模块的完整支持存在版本前提(文档中的CppModuleVersionNotice组件会提示具体版本条件)。C# 模块还可通过spacetime publish --native-aot启用 NativeAOT-LLVM 编译(实验特性,支持 Windows,以及 .NET 10 环境下的 Linux),相关参数定义可见 publish.rs。
数据库命名规则
当你发布一个模块时,需要为数据库起一个名字。数据库名必须匹配正则表达式/^[a-z0-9]+(-[a-z0-9]+)*$/,即:只能包含小写 ASCII 字母和数字,并用连字符(-)分隔。
合法示例:
my-game-serverchat-app-productiontest123
该正则的具体实现位于 name.rs,其parse_database_name函数逐字符校验,可总结出以下更精细的约束规则:
- 名字不能为空;
- 首字符必须是
a-z0-9,不能以-开头; - 不能以
-结尾; - 不能出现连续两个
-; - 除小写字母与数字外的任何字符(包括大写字母、下划线、空格)都会报错;
- 名字不能是 identity 字符串(即不能把数据库身份标识当作名字使用,
DatabaseNameError::Identity会拒绝此类输入)。
每个数据库在创建时还会获得一个唯一的 identity(十六进制字符串)。客户端既可以用名字连接,也可以用 identity 连接。在 CLI 内部,validate_name_or_identity(见 publish.rs)会先判断参数是否为 identity,若不是则走上述数据库名校验;如果误将 identity 当作普通名字,parse_database_name会给出明确的「数据库名不能是 identity」错误。
使用 spacetime CLI 管理数据库
模块与数据库的日常管理全部通过spacetimeCLI 工具完成。下面按生命周期顺序逐一讲解,并补充源码中的参数细节。
创建与更新数据库(spacetime publish)
创建或更新数据库的唯一方式是发布你的模块:
spacetime publish <DATABASE_NAME>该命令的完整行为可参见spacetime publish详解文档 与 CLI 参考。从 publish.rs 的cli()定义可看到,spacetime publish还支持以下常用参数:
| 参数 | 作用 |
|---|---|
<DATABASE_NAME> | 数据库名或 identity;若传parent/child形式则同时指定父数据库 |
-p, --module-path <PATH> | 模块项目路径(默认优先取spacetimedb/子目录,再取当前目录) |
-b, --bin-path <PATH> | 跳过构建,直接发布编译好的 Wasm 二进制 |
-j, --js-path <PATH> | 不稳定:跳过构建,直接发布 JS 文件(TypeScript 模块) |
--build-options <OPTS> | 传递给构建命令的选项(如--build-options='--lint-dir=') |
--break-clients | 允许对已存在数据库做破坏性变更(跳过「将破坏现有客户端」确认,等价于--yes=break-clients;但不会强制发布会导致数据删除的变更) |
--clear-database | 清空数据库数据后发布(always/on-conflict/never,需配合名字使用) |
--parent <DOMAIN_OR_IDENTITY> | 为数据库指定父数据库(仅创建时生效),新数据库会继承父数据库的团队权限 |
--organization <NAME_OR_IDENTITY> | 将数据库创建到某个组织下(仅创建时生效),组织的成员权限会应用于新数据库 |
--yes[=<类别>] | 跳过确认提示,取值可为all、remote、migrate、break-clients、skip-login、delete-data(可逗号分隔或用多个--yes=),需用=连接 |
--no-config | 忽略spacetime.json配置 |
--env <ENV> | 配置文件分层环境名(如 dev、staging) |
--num-replicas <N> | 不稳定:数据库副本数 |
--native-aot | C# 模块使用 NativeAOT-LLVM 编译(实验特性) |
重发布时的迁移行为:当你对已存在的数据库重新发布时,SpacetimeDB 会先调用pre_publish接口做「破坏性变更检查」(CLI 输出Checking for breaking changes...)。根据 publish.rs 中apply_pre_publish_if_needed的实现,检查结果分为两种情况:
- AutoMigrate(自动迁移):打印迁移计划;若变更会破坏现有客户端(
break_clients为 true),会要求确认「The above changes will BREAK existing clients」,可通过--break-clients或--yes=break-clients跳过。 - ManualMigrate(手动迁移):打印原因并中止发布,除非指定了
--clear-database=on-conflict(此时会清库重发,需要--yes=delete-data确认)。 - 若目标数据库不存在(HTTP 404),则视为全新发布,跳过全部检查。
此外,若检测到主版本升级(如 1.x → 2.0),CLI 会要求手动输入upgrade确认,无法通过常规--yes静默跳过,因为此操作不可回退。相关细节可参考 1.x 到 2.0 升级说明。
迁移进阶主题:
- 自动迁移(Automatic Migrations) —— 哪些 schema 变更是安全的、破坏性的或禁止的。
- 增量迁移(Incremental Migrations) —— 处理复杂 schema 变更的高级模式。
删除数据库(spacetime delete)
永久删除一个数据库及其全部数据:
spacetime delete <DATABASE_NAME>CLI 会提示你确认删除操作;在脚本中可用--yes跳过确认(对应 delete.rs 中的force标志,提示语为 "Are you sure you want to delete database ...? This action cannot be undone.")。
警告:删除数据库是永久性操作,无法撤销,所有数据都会丢失。
从 delete.rs 源码看,删除还包含一个安全细节:如果目标数据库存在子数据库(通过--parent建立的数据库树),服务端会返回428 PRECONDITION_REQUIRED,CLI 会打印整棵数据库树(类似tree命令的树形结构,展示各节点的 identity 与关联名字),并要求二次确认「Deleting the database ... will also delete its children!」。确认后会携带confirmation_token再次发起删除请求。可用--no-config忽略spacetime.json中的数据库目标。更多选项见 CLI 参考。
用 SQL 查询数据库(spacetime sql)
可以直接对数据库执行 SQL 查询:
spacetime sql <DATABASE_NAME> "SELECT * FROM user"所有者权限(Owner Privileges)
重要:以数据库所有者身份执行 SQL 查询时,会绕过表可见性限制——也就是说,你可以查询普通客户端无法访问的私有表。
若想以无特权客户端视角测试查询结果,使用--anonymous标志:
spacetime sql --anonymous <DATABASE_NAME> "SELECT * FROM user"该查询会以匿名客户端身份执行,严格遵守表可见性规则。
从 sql.rs 源码可补充以下实用细节:
--interactive:进入交互式 SQL 提示符模式(spacetime sql [database] --interactive),底层调用 REPL 循环。--format <FORMAT>:输出格式,默认为text(psql 风格表格,用+/-分隔),也可指定json输出原始 JSON 结果。- 执行 DML 语句时,结果表格下方会附带统计信息,例如
(0 rows) [inserted: 1, deleted: 1, updated: 1, server: 1.00ms],展示插入/删除/更新的行数与服务端耗时(该行为由StmtResult的Display实现产生,相关测试见 sql.rs 中的test_output等用例)。 - 未显式指定数据库时,若项目根目录存在
spacetime.json,会自动使用其中的数据库目标。
更多 SQL 选项见 CLI 参考,SQL 语法可参考 SQL 参考文档。
查看日志(spacetime logs)
查看数据库日志:
spacetime logs <DATABASE_NAME>实时跟随日志
类似tail -f的流式日志输出:
spacetime logs --follow <DATABASE_NAME>该命令会保持连接打开并持续显示新产生的日志条目,按Ctrl+C停止。从 logs.rs 源码看,--follow且未指定行数时默认先输出最近 10 行再开始跟随。
限制日志输出量
只查看最后 N 行:
spacetime logs --num-lines 100 <DATABASE_NAME>--num-lines(或-n)用于指定从日志开头起打印的行数;若完全不指定则返回全部日志。
日志等级过滤
logs.rs 还提供了两个实用过滤参数:
-l, --level <LEVEL>:按严重级别过滤,级别从低到高为trace、debug、info、warn、error、panic,只显示达到或超过该级别的日志;--level-exact:配合--level使用,只显示恰好等于该级别的日志。
文本模式下终端还会按级别着色(如 ERROR 红色、WARN 黄色、INFO 蓝色等),支持--format json输出结构化日志。更多日志选项见 CLI 参考,模块内如何打日志可参考 日志指南。
列出你的数据库(spacetime list)
查看当前身份关联的全部数据库:
spacetime list该命令会显示数据库名、identity 与所在主机服务器。从 list.rs 源码看,它以当前登录用户的 identity 查询/v1/identity/{identity}/databases接口,再对每个数据库做反向 DNS 解析得到名字,最终以 psql 风格表格输出,表头为Database Name(s)与Identity(同一 identity 可能关联多个名字,会以逗号分隔列出)。
通过网站管理数据库
除了 CLI,还可以通过 SpacetimeDB 的 Web 界面(spacetimedb.com)管理数据库,支持:
- 查看指标(View metrics)—— 监控数据库性能、连接数与资源使用;
- 浏览表(Browse tables)—— 查看表 schema 与数据;
- 查看日志(View logs)—— 访问带过滤与搜索的历史日志;
- 管理访问权限(Manage access)—— 控制数据库权限与团队访问;
- 监控查询(Monitor queries)—— 查看订阅查询与 reducer 调用。
网站为大部分 CLI 操作提供了图形化界面,便于可视化地查看和管理数据库。
Projects 与 Teams
SpacetimeDB 支持将数据库组织为项目(Projects)并管理团队访问(team access),从而:
- 将相关的数据库分组管理;
- 与团队成员共享访问权限;
- 在项目层面统一管理权限。
此外,如前文所述,数据库之间还可以通过--parent建立父子层级(子数据库继承父数据库的团队权限),这为多环境、多租户的权限组织提供了更细的粒度。
学习路径
快速上手
如果你是 SpacetimeDB 新手,推荐按以下顺序学习:
- 创建你的第一个数据库模块—— 用
spacetime init或spacetime dev搭建模块项目; - 构建并发布—— 学习如何编译并部署模块;
- 定义表—— 用表、列与索引组织数据;
- 编写 Reducers—— 创建以事务方式修改数据库的函数;
- 连接客户端—— 构建连接数据库的客户端应用。
核心概念
掌握基础后,继续深入这些核心主题:
- 错误处理(Error Handling)—— 在 reducers 中优雅处理错误;
- 生命周期 Reducers(Lifecycle Reducers)—— 响应初始化、客户端连接等系统事件;
- 自动迁移(Automatic Migrations)—— 理解 schema 变更如何生效;
- 日志(Logging)—— 用日志调试和监控模块。
高级特性
- Procedures—— 发起 HTTP 请求、与外部服务交互;
- Views—— 创建可计算、可订阅的查询;
- 调度表(Schedule Tables)—— 在指定时间调度 reducers 运行;
- 增量迁移(Incremental Migrations)—— 处理复杂 schema 变更;
- SQL 查询—— 用 SQL 查询数据库。
部署上线
- 部署到 MainCloud—— 将数据库托管到 SpacetimeDB 的托管服务;
- 自托管(Self-Hosting)—— 运行自己的 SpacetimeDB 实例(仓库内对应的独立服务器入口与配置见 standalone 与 config.toml)。
下一步
- 学习 Tables 定义数据库 schema;
- 创建 Reducers 修改数据库状态;
- 理解 Subscriptions(订阅) 实现实时数据同步;
- 查阅 CLI 参考 了解全部可用命令。
【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考