Данные · Урок 22

Базы данных и CRUD

Массивы в памяти исчезают с перезапуском сервера. База данных хранит данные постоянно и умеет искать их быстро. Разберём SQL, SQLite и классические операции CRUD.

SQLite: база «в файле»

SQLite хранит базу одним файлом — идеально для старта (для больших нагрузок позже возьмёте PostgreSQL или MongoDB). Подключается к Node.js через пакет better-sqlite3.

npm install better-sqlite3

const Database = require("better-sqlite3");
const db = new Database("shop.db");

db.exec(`
  CREATE TABLE IF NOT EXISTS products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    price REAL NOT NULL
  )
`);

CRUD: четыре действия

Create — создать, Read — прочитать, Update — изменить, Delete — удалить. В SQL каждой операции своя команда.

// Create
db.prepare("INSERT INTO products (name, price) VALUES (?, ?)")
  .run("Кружка", 450);

// Read (список и один)
const rows = db.prepare("SELECT * FROM products").all();
const one  = db.prepare("SELECT * FROM products WHERE id = ?").get(1);

// Update
db.prepare("UPDATE products SET price = ? WHERE id = ?").run(500, 1);

// Delete
db.prepare("DELETE FROM products WHERE id = ?").run(1);
💡
Знаки ? в запросах — это параметры. Значения подставляются отдельно, и SQLite сам экранирует их. Так SQL-инъекции (подстановка чужих команд в строку) становятся невозможными.

Связка с Express

Маршруты API читают базу и возвращают JSON — фронт получает те же данные, что мы рисовали массивами в уроках-проектах.

app.get("/products", (req, res) => {
  res.json(db.prepare("SELECT * FROM products").all());
});

app.post("/products", (req, res) => {
  const { name, price } = req.body;
  const info = db.prepare("INSERT INTO products (name, price) VALUES (?, ?)")
    .run(name, price);
  res.status(201).json({ id: info.lastInsertRowid });
});
ℹ️
better-sqlite3 синхронный — для учебного проекта это упрощение выглядит удобно и понятно. В проде обычно берут асинхронные драйверы, но синтаксис SQL тот же.

Что запомнить