关于 cloudflare-d1
面向开发者的 Cloudflare D1 使用指南,介绍如何从 Workers 访问无服务器 SQLite 数据库,并涵盖配置、查询、迁移及批处理和读取复制等模式。
主要功能
- 01数据库与绑定配置
- 02预处理语句和批量查询
- 03架构迁移指导
- 04读取复制模式
- 05SQLite 类型与查询实践
适用场景
- 01为 Worker 创建 D1 数据库
- 02应用并测试架构迁移
- 03以原子批次执行数据库操作
- 04通过副本提供全球读取
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ secondsky/ claude-skills --skill cloudflare-d1安装后在 Claude Code 中输入/cloudflare-d1确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/2025-features.mdbest-practices.mdlimits.mdmetrics-analytics.mdquery-patterns.mdread-replication.mdsetup-guide.mdtemplates/d1-setup-migration.shd1-worker-queries.tsschema-example.sql详细介绍
Cloudflare D1 数据库
状态:已可用于生产环境 ✅ | 上次验证:2025-01-15
目录
什么是 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 查看完整操作指南。
关键规则
务必做到 ✅
- 使用预处理语句和
.bind()(切勿拼接字符串) - 为 WHERE/JOIN/ORDER BY 列创建索引
- 使用迁移进行架构变更(切勿手动执行 SQL)
- 批量执行查询以完成多项操作(.batch())
- 在架构变更后运行 PRAGMA optimize
- 显式处理错误(try/catch)
- 时间戳使用 INTEGER(Date.now())
- 部署迁移前先在本地测试
- 使用读取副本提升全球读取性能
- 在 SQL 查询前验证输入
切勿这样做 ❌
- 切勿将用户输入拼接到 SQL 中
- 切勿将 database_id 提交到公开仓库
- 切勿跳过迁移进行架构变更
- 切勿使用 VARCHAR(改用 TEXT)
- 切勿遗漏筛选列的索引
- 切勿忽视 SQLite 类型亲和性规则
- **切勿在没有 LIMIT 的情况下使用 SELECT ***
- 切勿在未于本地测试的情况下运行迁移
- 每行大小切勿超过 1 MB
- 切勿使用 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, INT | INTEGER |
| TEXT, VARCHAR, CHAR | TEXT |
| REAL, FLOAT, DOUBLE | REAL |
| BLOB | BLOB |
| (无类型) | BLOB |
最佳实践:
- 数值使用
INTEGER - 字符串使用
TEXT(而非 VARCHAR) - 时间戳使用
INTEGER(Date.now()) - 二进制数据使用
BLOB
可避免的 5 大错误
- SQL 注入:使用
.bind(),切勿拼接字符串 - 缺少索引:为 WHERE/JOIN 列创建索引
- 迁移失败:先在本地测试
- 类型混淆:时间戳使用 INTEGER
- 批次大小:每批限制在 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 强制执行。
官方文档
- D1 概览:https://developers.cloudflare.com/d1/
- 快速入门:https://developers.cloudflare.com/d1/get-started/
- 客户端 API:https://developers.cloudflare.com/d1/build-with-d1/d1-client-api/
- 读取复制:https://developers.cloudflare.com/d1/reference/read-replication/
有问题?遇到故障?
- 查看
references/setup-guide.md了解设置 - 查看
references/query-patterns.md了解 API 参考 - 查看
references/read-replication.md了解全局读取 - 加载
references/best-practices.md进行优化