資料庫選項

本頁內容

EmDash 支援多種資料庫後端。根據你的部署目標選擇。

概覽

資料庫最適用於部署
D1Cloudflare Workers邊緣,全球分散
HyperdriveCloudflare Workers 上的 PostgreSQL邊緣,現有 Postgres
PostgreSQL生產 Node.js有 Postgres 的任何平台
libSQL遠端資料庫邊緣或 Node.js
SQLiteNode.js,本地開發單一伺服器

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.jsonc

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

wrangler.toml

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

唯讀副本

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 獲得 read-your-writes 一致性。
"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

資料庫角色要求

EmDash 建立和更新自己的 PostgreSQL 表。核心遷移建立和修改系統及集合表,內容類型建立 ec_* 表,新增或移除欄位會修改其集合表。因此設定的 PostgreSQL 角色在網站的整個生命週期內都需要架構權限。

為 EmDash 使用一個標準角色。它需要:

  • 資料庫的 CONNECT
  • 活動架構的 USAGECREATE
  • 每個 EmDash 表和函式的擁有權;以及
  • 這些表的 SELECTINSERTUPDATEDELETE

大多數安裝可以使用資料庫的現有架構(通常是 public)。使用管理連線授予存取權限:

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

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

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

可選:使用專用架構

當 EmDash 與另一個應用共享資料庫時,使用專用架構來隔離其物件:

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;

連線池

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

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

Hyperdrive

使用 hyperdrive() 配接器在 Cloudflare Workers 上執行 EmDash,後端使用現有的 PostgreSQL 資料庫。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 的毫秒數
migrationConnectionStringEnvstringCLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_<BINDING>包含直接 PostgreSQL origin URL 的環境變數
maxnumber5Worker 內到 Hyperdrive 的連線池最大大小

從快取提供匿名讀取

預設完全停用 Hyperdrive 快取。但使用 GETHEAD 的匿名公開請求可以容忍短暫的過時視窗。如果可以接受,在同一資料庫上執行兩個 Hyperdrive 設定:一個快取關閉(主 binding),一個快取開啟(cachedBinding)。

這是 Cloudflare 記錄的雙設定模式

修復 PostgreSQL 混合擁有權

如果網站使用了多個 PostgreSQL 使用者,首先選擇主 EmDash 連線將繼續使用的標準角色。備份並在修復擁有權期間停止架構變更。

檢查活動架構中的每個表:

SELECT
  n.nspname AS schema_name,
  c.relname AS table_name,
  pg_get_userbyid(c.relowner) AS owner
FROM pg_class AS c
JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE n.nspname = current_schema()
  AND c.relkind IN ('r', 'p')
ORDER BY c.relname;

使用架構限定名稱轉移不匹配的物件:

ALTER TABLE emdash.content_taxonomies OWNER TO emdash_app;
ALTER TABLE emdash.ec_posts OWNER TO emdash_app;
ALTER FUNCTION emdash.emdash_media_usage_capture_work() OWNER TO emdash_app;

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}` });

遷移

EmDash 預設為所有支援的方言自動執行核心遷移。Astro build 和 sync 還會輸出經過驗證的無密鑰 .emdash/migrations.jsonemdash migrate 可以在部署前套用。

參見管理核心資料庫遷移了解目標憑證、CI 序列化、auto/check/manual 執行階段策略和復原指引。

如果資料庫為空(無集合)且設定精靈未完成,EmDash 還會在首次啟動時套用種子檔案。種子從 .emdash/seed.jsonpackage.json#emdash.seed 中的路徑或 seed/seed.json 讀取,並在編譯時內嵌到建置中。

基於環境的設定

每個環境使用不同的資料庫:

import { sqlite, libsql, postgres } from "emdash/db";
import { d1 } from "@emdash-cms/cloudflare";

const database = import.meta.env.PROD ? d1({ binding: "DB" }) : sqlite({ url: "file:./data.db" });

export default defineConfig({
	integrations: [emdash({ database })],
});

選擇也可以基於環境變數而非建置模式:

const database = process.env.DATABASE_URL
	? postgres({ connectionString: process.env.DATABASE_URL })
	: sqlite({ url: "file:./data.db" });