D1 数据库
Cloudflare D1 是一个基于 SQLite 的边缘数据库,专为 Cloudflare Workers 设计。它提供低延迟的数据库访问,非常适合构建全栈应用。
D1 简介
什么是 D1?
D1 是 Cloudflare 提供的无服务器 SQL 数据库,基于 SQLite 构建。它将数据库部署到边缘节点,让数据更接近用户。
D1 的特点
SQLite 兼容:使用熟悉的 SQL 语法,支持大多数 SQLite 功能。
边缘部署:数据库在边缘节点运行,延迟极低。
自动复制:数据自动复制到多个位置,保证高可用。
与 Workers 深度集成:直接在 Worker 中访问数据库。
免费额度
| 资源 | 免费额度 |
|---|---|
| 存储空间 | 5GB |
| 读取行数 | 500 万行/月 |
| 写入行数 | 10 万行/月 |
快速开始
创建数据库
使用 Wrangler CLI 创建数据库:
# 创建数据库
npx wrangler d1 create my-database
输出会显示数据库 ID,保存这个 ID 用于配置。
配置绑定
在 wrangler.toml 中添加绑定:
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "your-database-id"
创建表
创建 SQL 文件 schema.sql:
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
user_id INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
执行 SQL:
# 本地数据库
npx wrangler d1 execute my-database --local --file=./schema.sql
# 远程数据库
npx wrangler d1 execute my-database --remote --file=./schema.sql
在 Workers 中使用 D1
查询数据
export default {
async fetch(request, env, ctx) {
const result = await env.DB.prepare(
'SELECT * FROM users ORDER BY created_at DESC'
).all();
return Response.json(result.results);
},
};
参数化查询
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const id = url.searchParams.get('id');
const result = await env.DB.prepare(
'SELECT * FROM users WHERE id = ?'
).bind(id).first();
if (!result) {
return new Response('Not Found', { status: 404 });
}
return Response.json(result);
},
};
插入数据
export default {
async fetch(request, env, ctx) {
const body = await request.json();
const result = await env.DB.prepare(
'INSERT INTO users (name, email) VALUES (?, ?)'
).bind(body.name, body.email).run();
return Response.json({
id: result.meta.last_row_id,
success: result.success
});
},
};
更新数据
export default {
async fetch(request, env, ctx) {
const body = await request.json();
const result = await env.DB.prepare(
'UPDATE users SET name = ?, email = ? WHERE id = ?'
).bind(body.name, body.email, body.id).run();
return Response.json({
changes: result.meta.changes,
success: result.success
});
},
};
删除数据
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const id = url.searchParams.get('id');
const result = await env.DB.prepare(
'DELETE FROM users WHERE id = ?'
).bind(id).run();
return Response.json({
success: result.success
});
},
};
批量操作
批量插入
export default {
async fetch(request, env, ctx) {
const users = await request.json();
const statements = users.map(user =>
env.DB.prepare(
'INSERT INTO users (name, email) VALUES (?, ?)'
).bind(user.name, user.email)
);
const results = await env.DB.batch(statements);
return Response.json({
inserted: results.length
});
},
};
事务
D1 支持事务操作:
export default {
async fetch(request, env, ctx) {
const body = await request.json();
try {
const result = await env.DB.batch([
env.DB.prepare('INSERT INTO users (name, email) VALUES (?, ?)')
.bind(body.name, body.email),
env.DB.prepare('INSERT INTO posts (title, user_id) VALUES (?, last_insert_rowid())')
.bind(body.firstPostTitle),
]);
return Response.json({ success: true });
} catch (error) {
return Response.json({ error: error.message }, { status: 500 });
}
},
};
使用 ORM
Drizzle ORM
Drizzle 是一个轻量级 TypeScript ORM,支持 D1:
npm install drizzle-orm drizzle-kit
配置 drizzle.config.ts:
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/schema.ts',
out: './drizzle',
dialect: 'sqlite',
driver: 'd1-http',
dbCredentials: {
accountId: 'your-account-id',
databaseId: 'your-database-id',
token: 'your-api-token',
},
});
定义 Schema:
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
email: text('email').notNull().unique(),
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => new Date()),
});
使用 ORM:
import { drizzle } from 'drizzle-orm/d1';
import { users } from './schema';
import { eq } from 'drizzle-orm';
export default {
async fetch(request, env, ctx) {
const db = drizzle(env.DB);
const allUsers = await db.select().from(users);
const user = await db.select().from(users)
.where(eq(users.id, 1));
await db.insert(users).values({
name: 'John',
email: '[email protected]',
});
return Response.json(allUsers);
},
};
REST API 示例
构建完整的 REST API:
import { Hono } from 'hono';
type Bindings = {
DB: D1Database;
};
const app = new Hono<{ Bindings: Bindings }>();
// 获取所有用户
app.get('/api/users', async (c) => {
const result = await c.env.DB.prepare(
'SELECT * FROM users ORDER BY created_at DESC'
).all();
return c.json(result.results);
});
// 获取单个用户
app.get('/api/users/:id', async (c) => {
const id = c.req.param('id');
const result = await c.env.DB.prepare(
'SELECT * FROM users WHERE id = ?'
).bind(id).first();
if (!result) {
return c.json({ error: 'Not Found' }, 404);
}
return c.json(result);
});
// 创建用户
app.post('/api/users', async (c) => {
const body = await c.req.json();
const result = await c.env.DB.prepare(
'INSERT INTO users (name, email) VALUES (?, ?)'
).bind(body.name, body.email).run();
return c.json({ id: result.meta.last_row_id }, 201);
});
// 更新用户
app.put('/api/users/:id', async (c) => {
const id = c.req.param('id');
const body = await c.req.json();
const result = await c.env.DB.prepare(
'UPDATE users SET name = ?, email = ? WHERE id = ?'
).bind(body.name, body.email, id).run();
return c.json({ changes: result.meta.changes });
});
// 删除用户
app.delete('/api/users/:id', async (c) => {
const id = c.req.param('id');
await c.env.DB.prepare(
'DELETE FROM users WHERE id = ?'
).bind(id).run();
return c.json({ success: true });
});
export default app;
数据库管理
查看数据库列表
npx wrangler d1 list
执行单条 SQL
npx wrangler d1 execute my-database --command "SELECT * FROM users"
导出数据
npx wrangler d1 export my-database --output=backup.sql
查看数据库信息
npx wrangler d1 info my-database
常见问题
D1 和传统数据库有什么区别?
D1 是边缘数据库,数据存储在边缘节点,延迟更低。但它有存储和写入限制,适合中小型应用。
如何处理数据库迁移?
使用 Drizzle Kit 或手动管理 SQL 迁移文件:
npx drizzle-kit generate:sqlite
npx drizzle-kit push:sqlite
支持哪些 SQLite 功能?
D1 支持大多数 SQLite 功能,但不支持:
- ATTACH DATABASE
- PRAGMA 语句(部分)
- 用户定义函数
参考链接
下一步
完成 D1 学习后,接下来学习 KV 存储,了解如何使用键值存储。