Перейти к содержимому
WebShield Docs

База D1

Серверная база SQLite для функций — миграции, SQL-запросы из кода, импорт данных и лимиты. Всё с примерами.

D1 — серверная база SQLite, встроенная в функции. Это те же таблицы, столбцы, индексы и язык SQL, что в обычном SQLite: база живёт рядом с функцией и доступна ей по имени, без строк подключения. Одна функция может иметь несколько баз.

Для данных «положил — прочитал» без связей проще KV, для объекта с собственным состоянием — Durable Objects.

База объявляется в wrangler.jsonc в списке d1_databases:

{
"d1_databases": [
{ "binding": "DB", "database_name": "app-db", "database_id": "00000000-0000-0000-0000-000000000001" }
]
}
  • binding — имя переменной, под которой база видна в коде: env.DB.
  • database_name — имя, которое вы указываете в командах CLI.
  • database_id — уникальный идентификатор базы (UUID). У каждой базы свой; задаётся при создании и больше не меняется.

Схему базы ведут миграции — SQL-файлы с порядковым номером в каталоге migrations/. Каждая миграция применяется ровно один раз, по порядку номеров.

migrations/
├── 0001_users.sql
└── 0002_posts.sql

0001_users.sql:

CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

0002_posts.sql:

CREATE TABLE posts (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
body TEXT NOT NULL
);

Применить новые миграции — из каталога проекта:

Окно терминала
webshield apps d1 migrate --app api app-db

app-db здесь — это database_name из конфига. Команда упаковывает каталог проекта и применяет к базе миграции, которых ещё не было. Посмотреть, какие уже применены:

Окно терминала
webshield apps d1 migrations --app api app-db

Имя миграции (0001_users.sql) в базу не попадает — важно только содержимое и порядок. Уже применённый файл не стоит править: правка не откатится, а рассинхронизирует историю. Нужно изменение — добавляйте новую миграцию со следующим номером.

В коде база доступна как env.<binding>. Запросы идут через prepare с параметрами — так безопасно: значения подставляются как данные, а не как часть SQL.

export default {
async fetch(request, env) {
const url = new URL(request.url);
// Создать пользователя
if (url.pathname === "/users" && request.method === "POST") {
const { email } = await request.json();
const { meta } = await env.DB
.prepare("INSERT INTO users (email) VALUES (?1)")
.bind(email)
.run();
return Response.json({ id: meta.last_row_id }, { status: 201 });
}
// Список пользователей
if (url.pathname === "/users") {
const { results } = await env.DB
.prepare("SELECT id, email FROM users ORDER BY id")
.all();
return Response.json(results);
}
// Один пользователь по id
const id = url.pathname.split("/")[2];
const user = await env.DB
.prepare("SELECT id, email FROM users WHERE id = ?1")
.bind(id)
.first();
return user
? Response.json(user)
: Response.json({ error: "not found" }, { status: 404 });
},
};

Методы:

  • prepare(sql).bind(...).run() — запрос, меняющий данные (INSERT, UPDATE, DELETE, CREATE). Возвращает meta со сведениями вроде last_row_id.
  • prepare(sql).bind(...).all() — выборка; возвращает { results } — массив строк.
  • prepare(sql).bind(...).first() — первая строка выборки или null.
  • .raw() — выборка колонок как есть, без ключей-имён.

Параметры — всегда через ?1, ?2, … и .bind(...). Никогда не склеивайте SQL из строк запроса: "SELECT * FROM users WHERE id = " + id пропустит SQL-инъекцию.

Разовые запросы и заливку данных делают командой execute — она не требует, чтобы запрос жил в миграции:

Окно терминала
# Запрос одной строкой
webshield apps d1 execute --app api app-db --command "SELECT count(*) FROM users"
# Или SQL из файла (например, seed.sql)
webshield apps d1 execute --app api app-db --file seed.sql

seed.sql:

INSERT INTO users (email) VALUES
('anna@example.com'),
('boris@example.com');

Один запрос — до 100 КБ. Большие наборы данных оформляйте миграциями, а не одной командой execute.

  • Миграции — схема базы: таблицы, индексы. Меняются редко, применяются по порядку и отслеживаются.
  • execute — разовые операции: залить стартовые данные, проверить состояние, поправить строку.
  • prepare в коде — всё, что делает сама функция на запросах посетителей.
  • Функция должна быть уже выкачена — команды выполняются на её узлах и ходят к базе рядом с ними.
  • Миграции повторяются сами, если связь с функцией оборвалась: они учитывают применённые, повтор безопасен. execute не повторяется — запрос мог успеть выполниться, поэтому проверьте результат и запустите снова, если нужно.
  • История и вывод всех операций — во вкладке Данные.
  • Возврат к моменту возвращает и базу D1: вкладка Данные → Вернуть данные к моменту. Подробнее — в Функциях.