mcpField
C
cloudflare-d1

cloudflare-d1

github.com/secondsky数据与数据库240406 次安装5 周前更新
代码仓库

关于 cloudflare-d1

面向开发者的 Cloudflare D1 使用指南,介绍如何从 Workers 访问无服务器 SQLite 数据库,并涵盖配置、查询、迁移及批处理和读取复制等模式。

主要功能

  1. 01数据库与绑定配置
  2. 02预处理语句和批量查询
  3. 03架构迁移指导
  4. 04读取复制模式
  5. 05SQLite 类型与查询实践

适用场景

  1. 01为 Worker 创建 D1 数据库
  2. 02应用并测试架构迁移
  3. 03以原子批次执行数据库操作
  4. 04通过副本提供全球读取

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/secondsky/claude-skills --skill cloudflare-d1

安装后在 Claude Code 中输入/cloudflare-d1确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
2025-features.md
best-practices.md
limits.md
metrics-analytics.md
query-patterns.md
read-replication.md
setup-guide.md
templates/
d1-setup-migration.sh
d1-worker-queries.ts
schema-example.sql

详细介绍

Cloudflare D1 数据库

状态:已可用于生产环境 ✅ | 上次验证:2025-01-15

目录

  1. 什么是 D1?
  2. 快速入门
  3. 关键规则
  4. D1 API 方法
  5. 5 大使用场景
  6. 迁移最佳实践
  7. 常见模式
  8. SQLite 类型亲和性
  9. 预防的 5 大错误

什么是 D1?

Cloudflare D1 是边缘网络上的无服务器 SQLite:

  • 无需服务器的 SQL 数据库
  • 全球分布
  • 冷启动时间为零
  • 标准 SQLite 语法
  • 通过读取副本实现全球性能

🆕 2025 年新增功能

D1 在 2025 年全年迎来了重大更新:

性能(2025 年 1 月)
  • 全球延迟降低 40-60%(P50 查询耗时)
  • 为边缘执行优化了 SQLite 引擎
  • 降低了小于 100 MB 的数据库的冷启动影响
可靠性(2025 年 9 月)
  • 自动重试查询:发生暂时性故障时,读取查询最多重试 2 次
  • 对应用代码透明(记录在 wrangler tail 中)
可扩展性(2025 年 4 月)
  • 读取复制(公开测试版):在全球部署读取副本
  • 读取密集型工作负载的读取吞吐量最高可提升 2 倍
  • 用于读写分离的 Sessions API
合规性(2025 年 11 月)
  • 数据本地化:指定 EU/US 管辖区域,以满足 GDPR/数据主权要求
  • 通过 --jurisdiction 标志或 wrangler.jsonc 配置
⚠️ 重大变更(2025 年 2 月 10 日)
  • 强制执行免费套餐硬性限制:10 个数据库,每个 500 MB,每次调用 50 次查询
  • 超出限制会导致 429 错误(此前仅发出警告)
  • 操作:使用 wrangler d1 list 检查用量,并在需要时升级

完整详情:加载 references/2025-features.md


快速入门(5 分钟)

1. 创建数据库
bunx wrangler d1 create my-database

保存输出中的 database_id!

2. 配置绑定

添加到 wrangler.jsonc:

{
  "name": "my-worker",
  "main": "src/index.ts",
  "compatibility_date": "2025-10-11",
  "d1_databases": [
    {
      "binding": "DB",                    // env.DB
      "database_name": "my-database",
      "database_id": "<UUID>",
      "preview_database_id": "local-db"
    }
  ]
}
3. 创建迁移
bunx wrangler d1 migrations create my-database create_users

编辑 migrations/0001_create_users.sql:

CREATE TABLE IF NOT EXISTS users (
  user_id INTEGER PRIMARY KEY AUTOINCREMENT,
  email TEXT NOT NULL UNIQUE,
  username TEXT NOT NULL,
  created_at INTEGER NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);

PRAGMA optimize;
4. 应用迁移
# Local
bunx wrangler d1 migrations apply my-database --local

# Production
bunx wrangler d1 migrations apply my-database --remote
5. 从 Worker 查询
import { Hono } from 'hono';

type Bindings = {
  DB: D1Database;
};

const app = new Hono<{ Bindings: Bindings }>();

app.get('/users/:email', async (c) => {
  const { results } = await c.env.DB.prepare(
    'SELECT * FROM users WHERE email = ?'
  )
    .bind(c.req.param('email'))
    .all();

  return c.json(results);
});

export default app;

加载 references/setup-guide.md 查看完整操作指南。


关键规则

务必做到 ✅
  1. 使用预处理语句和 .bind()(切勿拼接字符串)
  2. 为 WHERE/JOIN/ORDER BY 列创建索引
  3. 使用迁移进行架构变更(切勿手动执行 SQL)
  4. 批量执行查询以完成多项操作(.batch())
  5. 在架构变更后运行 PRAGMA optimize
  6. 显式处理错误(try/catch)
  7. 时间戳使用 INTEGER(Date.now())
  8. 部署迁移前先在本地测试
  9. 使用读取副本提升全球读取性能
  10. 在 SQL 查询前验证输入
切勿这样做 ❌
  1. 切勿将用户输入拼接到 SQL 中
  2. 切勿将 database_id 提交到公开仓库
  3. 切勿跳过迁移进行架构变更
  4. 切勿使用 VARCHAR(改用 TEXT)
  5. 切勿遗漏筛选列的索引
  6. 切勿忽视 SQLite 类型亲和性规则
  7. **切勿在没有 LIMIT 的情况下使用 SELECT ***
  8. 切勿在未于本地测试的情况下运行迁移
  9. 每行大小切勿超过 1 MB
  10. 切勿使用 DATETIME(时间戳请使用 INTEGER)

D1 API 方法

prepare() - 执行查询
// Single result
const { results } = await env.DB.prepare(
  'SELECT * FROM users WHERE email = ?'
)
  .bind(email)
  .all();

// First result only
const user = await env.DB.prepare(
  'SELECT * FROM users WHERE user_id = ?'
)
  .bind(userId)
  .first();

// Raw results (faster)
const { results } = await env.DB.prepare(
  'SELECT username FROM users'
)
  .raw();  // Returns arrays instead of objects
batch() - 执行多项查询
const results = await env.DB.batch([
  env.DB.prepare('INSERT INTO users (email, username, created_at) VALUES (?, ?, ?)')
    .bind('[email protected]', 'user1', Date.now()),
  env.DB.prepare('INSERT INTO users (email, username, created_at) VALUES (?, ?, ?)')
    .bind('[email protected]', 'user2', Date.now()),
  env.DB.prepare('SELECT COUNT(*) as count FROM users')
]);

console.log('Users count:', results[2].results[0].count);

所有查询都在单个事务中执行(全部成功或全部失败)。

exec() - 运行 SQL 字符串
// For migrations/setup only
await env.DB.exec(`
  CREATE TABLE IF NOT EXISTS users (
    user_id INTEGER PRIMARY KEY,
    email TEXT NOT NULL
  );
  CREATE INDEX idx_email ON users(email);
`);

切勿用于包含用户输入的查询!

加载 references/query-patterns.md 查看完整 API 参考。


5 大使用场景

使用场景 1:用户 CRUD
// Create
app.post('/users', async (c) => {
  const { email, username } = await c.req.json();

  const { results } = await c.env.DB.prepare(
    'INSERT INTO users (email, username, created_at) VALUES (?, ?, ?) RETURNING *'
  )
    .bind(email, username, Date.now())
    .all();

  return c.json(results[0]);
});

// Read
app.get('/users/:id', async (c) => {
  const user = await c.env.DB.prepare(
    'SELECT * FROM users WHERE user_id = ?'
  )
    .bind(c.req.param('id'))
    .first();

  if (!user) {
    return c.json({ error: 'Not found' }, 404);
  }

  return c.json(user);
});

// Update
app.patch('/users/:id', async (c) => {
  const { username } = await c.req.json();

  await c.env.DB.prepare(
    'UPDATE users SET username = ?, updated_at = ? WHERE user_id = ?'
  )
    .bind(username, Date.now(), c.req.param('id'))
    .run();

  return c.json({ success: true });
});

// Delete
app.delete('/users/:id', async (c) => {
  await c.env.DB.prepare(
    'DELETE FROM users WHERE user_id = ?'
  )
    .bind(c.req.param('id'))
    .run();

  return c.json({ success: true });
});
使用场景 2:批量操作
app.post('/users/bulk', async (c) => {
  const users = await c.req.json();  // Array of users

  const statements = users.map(user =>
    c.env.DB.prepare(
      'INSERT INTO users (email, username, created_at) VALUES (?, ?, ?)'
    ).bind(user.email, user.username, Date.now())
  );

  const results = await c.env.DB.batch(statements);

  return c.json({ inserted: results.length });
});
使用场景 3:读取复制(全球读取)
// Configure read replica (any region)
const session = c.env.DB.withSession({
  preferredRegion: 'auto'  // or 'weur', 'wnam', 'enam', 'apac'
});

// Read from nearest replica
const { results } = await session.prepare(
  'SELECT * FROM users WHERE email = ?'
)
  .bind(email)
  .all();

// Check which region served request
console.log('Served by:', results[0].served_by_region);

加载 references/read-replication.md 查看完整指南。

使用场景 4:使用 batch 的事务
// Transfer credits between users (atomic)
const results = await c.env.DB.batch([
  c.env.DB.prepare(
    'UPDATE users SET credits = credits - ? WHERE user_id = ?'
  ).bind(amount, fromUserId),
  c.env.DB.prepare(
    'UPDATE users SET credits = credits + ? WHERE user_id = ?'
  ).bind(amount, toUserId),
  c.env.DB.prepare(
    'INSERT INTO transactions (from_user, to_user, amount, created_at) VALUES (?, ?, ?, ?)'
  ).bind(fromUserId, toUserId, amount, Date.now())
]);

// All succeed or all fail (transaction)
使用场景 5:分页
app.get('/users', async (c) => {
  const page = parseInt(c.req.query('page') || '1');
  const limit = 20;
  const offset = (page - 1) * limit;

  const { results } = await c.env.DB.prepare(
    'SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?'
  )
    .bind(limit, offset)
    .all();

  return c.json({
    users: results,
    page,
    limit
  });
});

迁移最佳实践

1. 务必使用迁移
bunx wrangler d1 migrations create my-database add_users_avatar
2. 让迁移具备幂等性
-- ✅ GOOD: Idempotent
CREATE TABLE IF NOT EXISTS users (...);
CREATE INDEX IF NOT EXISTS idx_email ON users(email);
DROP TABLE IF EXISTS old_table;

-- ❌ BAD: Fails on re-run
CREATE TABLE users (...);
CREATE INDEX idx_email ON users(email);
3. 先在本地测试
bunx wrangler d1 migrations apply my-database --local
bunx wrangler d1 execute my-database --local --command "SELECT * FROM users"
4. 添加 PRAGMA optimize
-- End of migration
PRAGMA optimize;

加载 templates/schema-example.sql 获取完整的架构模板。


何时加载参考资料

在以下情况下加载 references/setup-guide.md:
  • 首次设置 D1
  • 创建第一个数据库
  • 配置绑定
  • 应用第一个迁移
在以下情况下加载 references/query-patterns.md:
  • 需要完整的 API 参考
  • 复杂的查询模式
  • 批量操作
  • 错误处理
在以下情况下加载 references/read-replication.md:
  • 设置全球读取
  • 需要实现全球低延迟
  • 了解 Sessions API
  • 需要顺序一致性
在以下情况下加载 references/best-practices.md:
  • 优化查询性能
  • 制定架构设计决策
  • 索引策略
  • 生产环境部署清单
在以下情况下加载 references/limits.md:
  • 遇到 429 错误或配额警告
  • 规划免费版与付费版的容量
  • 了解数据库/查询限制
  • 迁移到付费方案
在以下情况下加载 references/metrics-analytics.md:
  • 调查性能问题
  • 设置监控和告警
  • 使用 wrangler d1 insights 命令
  • 分析查询效率
在以下情况下加载 references/2025-features.md:
  • 从 v2.x 升级到 v3.x
  • 启用新功能(自动重试、司法辖区、复制)
  • 了解破坏性变更(2025 年 2 月 10 日开始强制执行)
  • 在截止日期前完成迁移
交互式工具

Agent(自主诊断):

  • agents/d1-debugger.md:9 阶段诊断(配置、迁移、查询、绑定、错误、限制、性能、Time Travel)
  • agents/d1-query-optimizer.md:性能分析(慢查询、缺失的索引、优化建议)

命令(交互式向导):

  • commands/cloudflare-d1:setup.md:交互式首次设置向导
  • commands/d1-create-migration.md:带验证的迁移创建向导

使用捆绑资源

参考资料(references/)
  • setup-guide.md - 完整的设置指南
  • query-patterns.md - 包含示例的完整 API 参考
  • read-replication.md - 全球只读副本设置
  • best-practices.md - 性能和优化
模板(templates/)
  • schema-example.sql - 包含索引的完整架构
  • d1-worker-queries.ts - Workers 中的所有查询模式
  • cloudflare-d1:setup-migration.sh - 完整的设置脚本

常见模式

错误处理
try {
  const { results } = await env.DB.prepare(
    'SELECT * FROM users WHERE email = ?'
  )
    .bind(email)
    .all();

  return c.json(results);
} catch (error) {
  console.error('D1 Error:', error);
  return c.json({ error: 'Database error' }, 500);
}
原始模式(性能)
// Returns arrays instead of objects (faster)
const { results } = await env.DB.prepare(
  'SELECT user_id, email FROM users'
)
  .raw();

// results = [[1, '[email protected]'], [2, '[email protected]']]
COUNT 查询
const count = await env.DB.prepare(
  'SELECT COUNT(*) as count FROM users'
)
  .first('count');  // Get single column value

console.log('Total users:', count);

SQLite 类型亲和性

D1 使用 SQLite 类型亲和性:

声明类型亲和性
INTEGER, INTINTEGER
TEXT, VARCHAR, CHARTEXT
REAL, FLOAT, DOUBLEREAL
BLOBBLOB
(无类型)BLOB

最佳实践:

  • 数值使用 INTEGER
  • 字符串使用 TEXT(而非 VARCHAR)
  • 时间戳使用 INTEGER(Date.now())
  • 二进制数据使用 BLOB

可避免的 5 大错误

  1. SQL 注入:使用 .bind(),切勿拼接字符串
  2. 缺少索引:为 WHERE/JOIN 列创建索引
  3. 迁移失败:先在本地测试
  4. 类型混淆:时间戳使用 INTEGER
  5. 批次大小:每批限制在 500 条语句以内

加载 references/best-practices.md 获取完整的错误预防指南。


安全安装

安装 D1 驱动程序包时,请遵循供应链安全最佳实践:

  • 阻止安装后脚本 — npm config set ignore-scripts true(或使用 Bun:默认已禁用)
  • 冷却期 — 等待 7 天,让社区审查新版本的软件包
  • 安装前审计 — 运行 socket package score npm <pkg>,或使用 socket npm install <pkg> 检查软件包

加载 dependency-upgrade 技能,获取完整的安全配置,包括 Socket CLI 集成、冷却期设置、锁文件验证和 CI 强制执行。

官方文档


有问题?遇到故障?

  1. 查看 references/setup-guide.md 了解设置
  2. 查看 references/query-patterns.md 了解 API 参考
  3. 查看 references/read-replication.md 了解全局读取
  4. 加载 references/best-practices.md 进行优化

评论

支持 Markdown