Используй better-sqlite3 с подготовленными запросами, транзакциями и отдельным репозиторием ради быстрого и безопасного хранения.
Открыть этот урок в KodokonSQLite работает внутри твоего процесса: ни сервера, ни сети, задержка на запрос порядка микросекунды. Именно поэтому синхронный API у better-sqlite3 не просто приемлем, а часто быстрее асинхронного драйвера: нет смысла платить промисом и оборотом цикла событий за чтение короче одного тика. Компромисс реален на записи: медленный запрос блокирует цикл. Держи запросы индексированными и короткими - и SQLite вытянет десятки тысяч чтений в секунду.
npm install better-sqlite3При открытии базы разницу делают две настройки. Режим WAL (write-ahead logging) разрешает чтение во время записи вместо блокировки всего файла. А схема применяется идемпотентно через CREATE TABLE IF NOT EXISTS - этого более чем достаточно, пока ты не завёл настоящий инструмент миграций.
import Database from 'better-sqlite3';
export function createDb(path = 'app.db') {
const db = new Database(path);
db.pragma('journal_mode = WAL');
db.exec(`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL
)`);
return db;
}Слой доступа к данным - репозиторий - единственный модуль, который говорит на SQL. Запросы подготавливаются один раз при создании и потом переиспользуются на каждом вызове: движок не разбирает текст SQL заново, а значения проходят через плейсхолдеры ?, но никогда через конкатенацию. Это ровно тот интерфейс findAll, findByEmail, insert, которого ждёт сервис из предыдущего урока.
export function createUserRepository(db) {
const insertStmt = db.prepare(
'INSERT INTO users (email, name) VALUES (?, ?)',
);
const byEmailStmt = db.prepare(
'SELECT * FROM users WHERE email = ?',
);
const allStmt = db.prepare(
'SELECT * FROM users ORDER BY id',
);
return {
insert(user) {
const info = insertStmt.run(user.email, user.name);
return { id: info.lastInsertRowid, ...user };
},
findByEmail(email) {
return byEmailStmt.get(email);
},
findAll() {
return allStmt.all();
},
};
}import { createDb } from './connection.js';
const db = createDb();
const insertStmt = db.prepare(
'INSERT INTO users (email, name) VALUES (?, ?)',
);
const insertMany = db.transaction((users) => {
for (const user of users) {
insertStmt.run(user.email, user.name);
}
});
insertMany([
{ email: 'ada@example.com', name: 'Ada' },
{ email: 'linus@example.com', name: 'Linus' },
]);? в подготовленном запросе?db.transaction для тысячи вставок?