選擇資料庫

本頁內容

為每個部署選擇一個資料庫配接器。資料庫保存內容模型、條目、使用者、設定和外掛資料。媒體二進位檔案屬於單獨的儲存後端

概述

資料庫使用場景執行環境
SQLite一個 Node.js 程序擁有持久化磁碟Node.js 或本機開發
D1站點在 Cloudflare Workers 上執行且應使用 Cloudflare SQLCloudflare Workers
Hyperdrive站點在 Workers 上執行且必須使用現有 PostgreSQL 來源Cloudflare Workers
PostgreSQL多個 Node.js 程序需要一個共用資料庫Node.js
libSQLNode.js 部署需要遠端 SQLite 相容資料庫Node.js

D1 是 Cloudflare 範本的預設選項。SQLite 是最簡單的 Node.js 選項,但需要一個可寫的持久卷和營運資料庫備份。

SQLite

SQLite 使用 Node.js 內建的資料庫驅動程式,是 Node.js 部署最簡單的選項。

import { sqlite } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: sqlite({ url: "file:./data.db" }),
		}),
	],
});

設定

選項型別描述
urlstringfile: 前綴的檔案路徑

檔案路徑

url 必須以 file: 開頭:

// 相對路徑
database: sqlite({ url: "file:./data/emdash.db" });

// 絕對路徑
database: sqlite({ url: "file:/var/data/emdash.db" });

// 從環境變數
database: sqlite({ url: `file:${process.env.DATABASE_PATH}` });

Cloudflare D1

D1 是 Cloudflare 的無伺服器 SQLite 資料庫。在部署到 Cloudflare Workers 時使用。

import { d1 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			database: d1({ binding: "DB" }),
		}),
	],
});

設定

選項型別預設值描述
bindingstringwrangler.jsonc 中的 D1 繫結名稱
sessionstring"disabled"讀取複寫模式(見下文)
bookmarkCookiestring"__em_d1_bookmark"工作階段書籤的 Cookie 名稱

Wrangler 繫結

wrangler.jsonc

{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "emdash-db"
    }
  ]
}

wrangler.toml

[[d1_databases]]
binding = "DB"
database_name = "emdash-db"

Wrangler 可以在部署期間從此繫結佈建缺失的 D1 資料庫。EmDash 遷移是單獨的步驟。完整的繫結集請參見部署到 Cloudflare,遷移操作手冊請參見管理核心資料庫遷移

讀取副本

D1 支援讀取複寫以降低全球分佈站點的讀取延遲。啟用後,讀取查詢會路由到附近的副本,而非始終存取主資料庫。

EmDash 使用 D1 Sessions API 來透明管理此功能。通過 session 選項啟用:

import { d1 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			database: d1({
				binding: "DB",
				session: "auto",
			}),
		}),
	],
});

工作階段模式

模式行為
"disabled"無工作階段。所有查詢傳送到主庫。預設值。
"auto"匿名請求從最近的副本讀取。經過驗證的使用者透過書籤 Cookie 取得寫後讀一致性。
"primary-first"類似 "auto",但第一個查詢始終傳送到主庫。用於寫入非常頻繁的站點。

運作方式

  • 匿名訪客 取得 first-unconstrained — 讀取從最近的副本進行以取得最低延遲。由於匿名使用者從不寫入,因此不需要一致性保證。
  • 經過驗證的使用者(編輯者、作者)取得基於書籤的工作階段。寫入後,書籤 Cookie 確保下一個請求至少看到該狀態。
  • 寫入請求POSTPUTDELETE)始終從主資料庫開始。
  • 建置時查詢(Astro Content Collections)完全繞過工作階段並直接使用主庫。

libSQL

libSQL 是 SQLite 的一個分支,支援遠端連線。當你需要遠端資料庫但不使用 Cloudflare D1 時使用。

import { libsql } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: libsql({
				url: process.env.LIBSQL_DATABASE_URL,
				authToken: process.env.LIBSQL_AUTH_TOKEN,
			}),
		}),
	],
});

設定

選項型別描述
urlstring資料庫 URL(libsql://...file:...
authTokenstring遠端資料庫的執行時驗證權杖(本機可選)
migrationAuthTokenEnvstring遷移權杖變數名(預設 TURSO_AUTH_TOKEN

本機開發

開發期間使用本機 libSQL 檔案:

database: libsql({ url: "file:./data.db" });

PostgreSQL

PostgreSQL 支援需要完整關聯式資料庫的 Node.js 部署。

import { postgres } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: postgres({
				connectionString: process.env.DATABASE_URL,
			}),
		}),
	],
});

設定

你可以使用連線字串或單獨的參數進行連線:

// 連線字串
database: postgres({
	connectionString: "postgres://user:password@localhost:5432/emdash",
});

// 單獨參數
database: postgres({
	host: "localhost",
	port: 5432,
	database: "emdash",
	user: "emdash",
	password: process.env.DB_PASSWORD,
	ssl: true,
});
選項型別描述
connectionStringstringPostgreSQL 連線 URL
hoststring資料庫主機
portnumber資料庫連接埠
databasestring資料庫名稱
userstring資料庫使用者
passwordstring資料庫密碼
sslboolean啟用 SSL
pool.minnumber連線池最小連線數(預設 0)
pool.maxnumber連線池最大連線數(預設 10)
pool.connectionTimeoutMillisnumber最大連線等待時間(pg 預設:0,無逾時)
pool.idleTimeoutMillisnumber閒置用戶端生存時間(pg 預設:10,000 ms)
migrationConnectionStringEnvstring遷移連線字串變數名(預設 DATABASE_URL

pool.connectionTimeoutMillis 設為非零值以限制當 PostgreSQL 不可達或沒有可用池化連線時請求的等待時間。將 pool.idleTimeoutMillis 設為 0 以保持閒置用戶端開放直到池關閉。省略任一選項將保留 pg 預設值。

資料庫角色要求

EmDash 建立和更新自己的 PostgreSQL 表。核心遷移建立和修改系統表和集合表,內容型別建立 ec_* 表,新增或移除欄位會修改其集合表。因此,配置的 PostgreSQL 角色需要在站點的整個生命週期內具有架構權限,而不僅僅是在初始設定期間。

為 EmDash 使用一個正規角色。它需要:

  • 資料庫的 CONNECT
  • 活動架構的 USAGECREATE
  • 每個 EmDash 表和函式的擁有權,直接或透過對擁有角色的 INHERIT 成員資格;以及
  • 這些表上的 SELECTINSERTUPDATEDELETE

它不需要是超級使用者,不需要 CREATEDBCREATEROLE,也不需要建立擴充功能。PostgreSQL 不提供表的 ALTERDROP 授權:這些操作屬於物件擁有者和繼承其權限的角色。向不同角色授予表的 ALL 不會使該角色成為擁有者。EmDash 不執行 SET ROLE,因此沒有繼承的成員資格是不夠的。

大多數安裝可以使用資料庫的現有架構,通常是 public。當資料庫專用於 EmDash 時,這是最簡單的選項。在下面的範例中,emdash_app 是 EmDash 連線字串中的登入角色;使用現有的提供者角色或建立專用登入。使用管理連線授予存取權限,替換你的資料庫、架構和角色名稱:

GRANT CONNECT ON DATABASE app TO emdash_app;
GRANT USAGE, CREATE ON SCHEMA public TO emdash_app;

這些授權允許角色建立新物件。它們不會變更現有表的擁有者;當現有站點有混合擁有者時,使用 PostgreSQL 擁有權修復操作手冊

EmDash 使用 PostgreSQL 的活動 current_schema()。它不建立架構也不設定 search_path,因此在部署前驗證連線:

SELECT
  current_database(),
  session_user,
  current_user,
  current_schema(),
  current_setting('search_path');

可選:使用專用架構

當 EmDash 與另一個應用程式共用資料庫,或者你想將其物件從 public 中隔離時,使用專用架構。這是可選的,在 EmDash 首次設定之前配置最為簡單。專用於 EmDash 的資料庫不需要單獨的架構。

假設正規角色 emdash_app 已存在,使用管理連線建立並選擇其架構:

GRANT CONNECT ON DATABASE app TO emdash_app;
CREATE SCHEMA emdash AUTHORIZATION emdash_app;
ALTER ROLE emdash_app IN DATABASE app SET search_path = emdash;

這不會從 public 移動現有安裝,也不會修復混合擁有權。現有站點應保持其目前架構,改為使用 PostgreSQL 擁有權修復操作手冊

連線池

配接器使用 pg.Pool。根據你的部署調整池大小:

database: postgres({
	connectionString: process.env.DATABASE_URL,
	pool: { min: 2, max: 20 },
});

Hyperdrive

使用 hyperdrive() 配接器在 Cloudflare Workers 上執行 EmDash,後端使用現有的 PostgreSQL — 或 Postgres 相容(如 PlanetScale Postgres)— 資料庫。Hyperdrive 透過 Cloudflare 網路池化和加速連線;EmDash 的 PostgreSQL 方言執行查詢。

import { hyperdrive, r2 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			database: hyperdrive({ binding: "HYPERDRIVE" }),
			storage: r2({ binding: "MEDIA" }),
		}),
	],
});

要求

  • 站點中安裝 pg >= 8.16.3pnpm add pg
  • compatibility_flags: ["nodejs_compat"]
  • compatibility_date >= "2024-09-23"

設定

首先準備 PostgreSQL 角色。然後使用該角色的連線字串建立 Hyperdrive 設定,並將繫結新增到 Wrangler 設定中:

wrangler hyperdrive create emdash-db \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full" \
  --caching-disabled

wrangler.jsonc

{
  "hyperdrive": [
    {
      "binding": "HYPERDRIVE",
      "id": "<your-hyperdrive-id>"
    }
  ]
}

wrangler.toml

[[hyperdrive]]
binding = "HYPERDRIVE"
id = "<your-hyperdrive-id>"

設定

選項型別預設值描述
bindingstring"HYPERDRIVE"主(快取停用)Hyperdrive 繫結名稱
cachedBindingstring可選的快取啟用繫結用於匿名讀取(見下文)
preferUncachedAfterWriteMsnumber60000*內容發佈後,在匿名公開讀取中優先使用 binding 持續該時間(ms)(與 Hyperdrive max_age 匹配)
migrationConnectionStringEnvstringCLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_<BINDING>包含 emdash migrate 直接 PostgreSQL 來源 URL 的環境變數
maxnumber5Worker 內到 Hyperdrive 連線池的最大大小

*預設值 60000 僅在設定了 cachedBinding 時適用;否則忽略。

從快取提供匿名讀取

預設情況下完全停用 Hyperdrive 快取,因為管理面板和寫入需要寫後讀一致性。但 使用 GETHEAD 的匿名公開請求可以容忍短暫的過期視窗。如果這個權衡可以接受,在同一個資料庫上執行兩個 Hyperdrive 設定:一個停用快取(主 binding)和一個啟用快取(cachedBinding)。EmDash 透過啟用快取的繫結路由這些匿名公開請求,透過未快取的主繫結路由其他所有請求。

# 主 — 快取關閉(用於管理、驗證請求、寫入、遷移)
wrangler hyperdrive create emdash-db \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full" \
  --caching-disabled

# 快取 — 相同的資料庫角色和連線字串,快取開啟
wrangler hyperdrive create emdash-db-cached \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full"
{
	"hyperdrive": [
		{ "binding": "HYPERDRIVE", "id": "<快取停用 ID>" },
		{ "binding": "HYPERDRIVE_CACHED", "id": "<快取啟用 ID>" }
	]
}
database: hyperdrive({ binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" });

這是 Cloudflare 為快取記錄的雙設定模式。EmDash 按請求決定使用哪個繫結:

  • 公開路徑的匿名讀取GET/HEAD,無工作階段,不在 /_emdash 下)→ 快取啟用的 cachedBinding除了內容發佈後的短暫視窗(預設 60s;將 preferUncachedAfterWriteMs 設為 Hyperdrive max_age),此時 EmDash 優先使用未快取的 binding,以防重建使用仍然過期的 Hyperdrive 結果重新填充邊緣/物件快取。
  • 驗證請求(編輯者、作者)→ 未快取的 binding
  • 變更請求POSTPUTPATCHDELETE,包括匿名)→ 未快取的 binding
  • /_emdash 下的任何請求(管理、設定、驗證、內部 API),即使是匿名 GET → 未快取的 binding
  • 執行時遷移和冷啟動 → 始終使用主 binding
  • 部署管理的遷移 → 使用 migrationConnectionStringEnv 直接連線到 PostgreSQL 來源;從不使用任何 Hyperdrive 繫結。

可選:使用單獨的快取角色

遷移、設定、驗證請求和明確寫入請求始終使用主 bindingcachedBinding 的單獨角色不需要架構擁有權或 CREATE,但需要 CONNECT、架構 USAGE 和公開站點使用的每個表上的 SELECT

匿名公開 GETHEAD 請求還可以記錄重新導向命中和 404。要保留這些功能,快取角色還需要 _emdash_redirects 上的 UPDATE_emdash_404_log 上的 SELECTINSERTUPDATEDELETE。在公開 GETHEAD 期間寫入的外掛或應用程式程式碼可能需要更多。除非你已使用受限快取角色測試了站點,否則對兩個繫結使用相同的角色。

在 EmDash 完成初始遷移後新增快取角色。以下範例使用可選的 emdash 架構;替換你的活動架構,如 public。使用你提供者的管理角色建立登入和資料庫設定:

CREATE ROLE emdash_cached LOGIN PASSWORD '替換為密鑰';
GRANT CONNECT ON DATABASE app TO emdash_cached;
ALTER ROLE emdash_cached IN DATABASE app SET search_path = emdash;

然後以架構和表的擁有者 emdash_app 連線,授予對現有和未來表的存取權限:

GRANT USAGE ON SCHEMA emdash TO emdash_cached;
GRANT SELECT ON ALL TABLES IN SCHEMA emdash TO emdash_cached;
GRANT UPDATE ON emdash._emdash_redirects TO emdash_cached;
GRANT SELECT, INSERT, UPDATE, DELETE ON emdash._emdash_404_log TO emdash_cached;

ALTER DEFAULT PRIVILEGES IN SCHEMA emdash
  GRANT SELECT ON TABLES TO emdash_cached;

使用兩個角色連線並驗證它們報告相同的 current_database()current_schema(),然後再啟用 cachedBinding。在共用架構上,GRANT SELECT ON ALL TABLES 也會暴露不相關的表。改為授予對單個 EmDash 表的存取權限,並在新增集合或其他架構物件時更新這些授權。

核心遷移

EmDash 預設為每個支援的方言自動執行核心遷移。Astro 建置和同步還會輸出經過驗證的、不含密鑰的 .emdash/migrations.jsonemdash migrate 可以在部署前套用。SQLite、libSQL、PostgreSQL、D1 和 Hyperdrive 背後的直接 PostgreSQL 來源都有部署執行器。

有關目標憑證、CI 序列化、auto/check/manual 執行時策略以及從未知記錄或模糊 D1 寫入中復原,請參見管理核心資料庫遷移

對於 PostgreSQL,執行時遷移透過配置的連線執行;Hyperdrive 執行時遷移始終使用主繫結。部署管理的 Hyperdrive 遷移直接連線到 PostgreSQL 來源。核心遷移可以建立表、索引和函式,修改或刪除欄和約束,以及更新現有列。能夠連線和修改列但不擁有現有 EmDash 物件的角色是不夠的。設定精靈無法修復缺失的資料庫權限,因為執行時遷移在設定之前執行。

如果資料庫為空(無集合)且設定精靈未完成,EmDash 還會在首次啟動時套用種子檔案。種子從 .emdash/seed.jsonpackage.json#emdash.seed 中的路徑或 seed/seed.json 讀取 — 以最先找到的為準 — 並在編譯時內聯到建置中。如果都不存在,則使用內建的預設種子。後續針對現有資料庫的啟動不會修改其內容。

為不同環境使用不同的資料庫

為開發、預覽、暫存和正式環境分別提供自己的資料庫。指向正式環境的預覽部署可能會對正式資料執行核心遷移或破壞性內容模型命令。

對於 Cloudflare,在對應的 Wrangler 環境下定義每個 D1 或 Hyperdrive 繫結,並向 Wrangler 命令傳遞 --env。對於 Node.js,為每個執行時環境注入不同的資料庫 URL。將憑證保存在執行時密鑰中,而不是 astro.config.mjs 中。