cloudflare学习笔记:cloudflare的D1里的数据有100万条,如何导出数据

229 阅读3分钟

从Cloudflare D1数据库导出数据

Cloudflare D1 是一个serverless的SQL数据库。你可以把D1想象成一个轻量级的MySQL或者SQLite,但它运行在 Cloudflare 的全球网络上,所以速度很快。这里介绍如何把D1数据库里面的数据导出来,以便备份、迁移或者做数据分析.

D1支持导出为两种格式:SQL 和 CSV.

  • SQL: 这种格式包含建表语句 (CREATE TABLE) 和插入数据的语句 (INSERT INTO),可以直接用来重建一个一模一样的数据库。
  • CSV: 这种格式是纯粹的数据,用逗号分隔,适合用Excel或者其他数据分析工具打开。

导出整个数据库

有两种方法可以导出整个 D1 数据库:

  1. 使用 D1AdminD1Admin 是一个图形化界面工具,可以方便地管理 D1 数据库。
    • 登录 D1Admin。
    • 找到 "导出" 选项卡。
    • 选择导出的格式(SQL 或 CSV)。
    • 选择要导出的内容(结构、数据、注释)。
    • 点击 "导出" 按钮,下载导出的文件。
  1. 使用 Wrangler CLIWrangler 是 Cloudflare 提供的命令行工具,可以用来管理 Cloudflare 的各种服务,包括 D1。打开终端,输入以下命令:
wrangler d1 export <database_name> --file=<output_file.sql>

例如:

wrangler d1 export my_database --file=backup.sql

这会将 my_database 数据库导出到 backup.sql 文件中。

    • <database_name>: 替换成你的 D1 数据库的名字。
    • <output_file.sql>: 替换成你想要保存的文件名。 例如 backup.sql

导出单个表

如果你只需要导出数据库中的某一个表,也可以这样做:

  1. 使用 D1Admin: 在 D1Admin 中选择要导出的表,然后按照导出整个数据库的步骤操作。
  2. 使用 Wrangler CLI: 使用 --table 参数指定要导出的表名。
wrangler d1 export <database_name> --table=<table_name> --file=<output_file.sql>

例如:

wrangler d1 export my_database --table=users --file=users.sql

这会将 my_database 数据库中的 users 表导出到 users.sql 文件中。

    • <table_name>: 替换成你要导出的表名。

实际应用例子

假设你有一个 D1 数据库,里面存储了网站的用户信息,你想定期备份这些数据。

  1. 使用 Wrangler CLI 创建一个备份脚本创建一个名为 backup.sh 的脚本文件,内容如下:
#!/bin/bash
# 数据库名称
DB_NAME="prod-users"
# 备份文件名,使用当前日期
FILE_NAME="backup_$(date +%Y%m%d).sql"
# 执行导出命令
wrangler d1 export $DB_NAME --file=$FILE_NAME
echo "Database $DB_NAME backed up to $FILE_NAME"

给脚本添加执行权限:

chmod +x backup.sh

然后,你可以每天定时运行这个脚本,自动备份你的数据。

  1. 使用导出的数据进行数据分析假设你导出了一个 CSV 文件,包含了用户的注册信息,你想分析用户的来源地。
    • 用 Excel 或者 Google Sheets 打开 CSV 文件。
    • 使用数据透视表功能,按照用户来源地进行分组,统计每个来源地的用户数量。
    • 生成图表,更直观地展示用户来源地的分布情况。

注意事项

  • 虚拟表不支持导出。 如果你的数据库包含虚拟表,需要先删除它们再进行导出。
  • 导出过程可能会阻塞数据库请求。 在高并发的情况下,导出会影响数据库的性能,建议在业务低峰期进行。

Cloudflare D1 常用 API 接口

Cloudflare D1 提供了一系列的 API 接口,用于和 D1 数据库进行交互。 这些接口允许你使用 SQL 语句来查询和操作数据.

常用 API 接口

  • 查询接口
    • stmt.all(): 返回所有行,结果是一个对象数组。每个对象代表一行数据,对象的属性名对应表的列名。
    • stmt.first([column]): 返回查询结果的第一行。 如果指定了 column,则只返回该列的值。
    • stmt.raw(): 执行原始 SQL 语句,返回结果。
  • 执行接口
    • stmt.run(): 执行一个 SQL 语句 (比如 INSERT, UPDATE, DELETE),并返回执行结果。
    • db.exec(): 执行一条 SQL 命令,并返回结果。 这个方法更通用,可以执行任何 SQL 命令。
  • 数据库管理
    • db.dump(): 导出数据库的当前状态。 这和前面讲的 wrangler d1 export 命令类似,可以用来备份数据库。

实际例子

假设你要构建一个简单的评论系统,使用 D1 数据库来存储评论数据.

  1. 创建表和插入数据
const createTable = await db.exec(`
  CREATE TABLE comments (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    content TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  );
`);

const insertComment = await db.run(`
  INSERT INTO comments (content) VALUES (?);
`, ["这是一个评论"]);

这段代码首先创建了一个名为 comments 的表,包含 id, contentcreated_at 三列。 id 是主键,自动递增;content 是评论内容;created_at 是评论创建时间,默认为当前时间。然后,插入了一条评论,内容是 "这是一个评论"。

  1. 查询数据
const comments = await db.all(`SELECT * FROM comments;`);
console.log(comments);

这段代码查询 comments 表中的所有数据,并将结果打印到控制台。 comments 是一个对象数组,每个对象代表一条评论。

  1. 创建 RESTful API你可以创建一个 RESTful API,让外部可以访问 D1 数据库。
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  if (request.method === 'POST' && request.url.endsWith('/api/all')) {
    const comments = await db.all(`SELECT * FROM comments;`);
    return new Response(JSON.stringify(comments), {
      headers: { 'Content-Type': 'application/json' },
    });
  }
  return new Response('Not Found', { status: 404 });
}

这段代码监听 fetch 事件,也就是当有 HTTP 请求进来时,会执行 handleRequest 函数。如果请求的方法是 POST,并且 URL 以 /api/all 结尾,那么就查询 comments 表中的所有数据,并将结果以 JSON 格式返回。如果请求的 URL 不是 /api/all,则返回 404 错误。要部署此代码,你需要创建一个 Cloudflare Worker,并将代码上传到 Worker 中。 然后,将 Worker 绑定到你的域名,就可以通过 HTTP 请求来访问 D1 数据库了.

注意事项

  • SQL 注入: 在使用 db.run()db.all() 方法时,要注意防止 SQL 注入攻击。 尽量使用参数化查询,避免直接拼接 SQL 语句。 例如,不要这样写:
const content = request.query.content; // 从 URL 参数中获取评论内容
const sql = `INSERT INTO comments (content) VALUES ('${content}')`; // 错误:存在 SQL 注入风险
await db.run(sql);

而应该这样写:

const content = request.query.content;
await db.run(`INSERT INTO comments (content) VALUES (?)`, [content]); // 正确:使用参数化查询

参数化查询可以有效地防止 SQL 注入攻击,提高应用程序的安全性。

  • 事务: D1 支持事务,可以保证多个 SQL 语句的原子性。 也就是说,要么全部执行成功,要么全部执行失败。 可以使用 db.batch() 方法来执行事务。
await db.batch([
  `INSERT INTO users (name, email) VALUES ('张三', 'zhangsan@example.com')`,
  `INSERT INTO users (name, email) VALUES ('李四', 'lisi@example.com')`,
]);

这段代码会将两条 INSERT 语句放在一个事务中执行。 如果其中一条语句执行失败,那么整个事务都会回滚,保证数据的一致性。

通过这些 API 接口,开发者可以灵活地管理和查询 D1 数据库中的数据,构建功能丰富的应用程序。