استخدم better-sqlite3 مع العبارات المُحضَّرة والمعاملات ومستودع مخصص من أجل حفظ سريع وآمن.
افتح هذا الدرس في Kodokonيعمل SQLite داخل عمليتك: دون خادم، ودون شبكة، وبزمن استجابة لكل استعلام في حدود الميكروثانية. وهذا ما يجعل واجهة better-sqlite3 المتزامنة (synchronous) ليست مقبولة فحسب، بل غالبًا أسرع من مُشغِّل غير متزامن: فلا جدوى من دفع ثمن وعد (promise) ودورة في حلقة الأحداث من أجل قراءة أقصر من نبضة (tick). والمقايضة حقيقية عند الكتابة: فالاستعلام البطيء يُعطِّل الحلقة. أبقِ استعلاماتك مفهرسة وقصيرة، وسيتعامل SQLite مع عشرات الآلاف من عمليات القراءة في الثانية.
npm install better-sqlite3عند فتح قاعدة البيانات، هناك إعدادان يُحدِثان الفارق. يتيح وضع WAL (التسجيل المُسبق للكتابة) عمليات القراءة أثناء الكتابة بدلًا من قفل الملف بأكمله. ويُطبَّق المخطط (schema) بطريقة عديمة التأثير الجانبي (idempotent) باستخدام CREATE TABLE IF NOT EXISTS - وهو أكثر من كافٍ قبل أن تُدخِل أداة ترحيل (migration) حقيقية.
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;
}إن طبقة الوصول إلى البيانات - المستودع (repository) - هي الوحدة الوحيدة التي تتحدث SQL. تُحضَّر الاستعلامات مرة واحدة عند الإنشاء ثم يُعاد استخدامها في كل استدعاء: فلا يُعيد المحرك تحليل نص SQL، وتمرّ القيم عبر العناصر النائبة (placeholders) ?، وليس أبدًا عبر الدمج (concatenation). إنها بالضبط الواجهة 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 لألف عملية إدراج؟