Kodokon kodokon.com

SQLite के साथ पर्सिस्टेंस: डेटा एक्सेस परत

तेज़, सुरक्षित पर्सिस्टेंस के लिए better-sqlite3 का उपयोग प्रिपेयर्ड स्टेटमेंट, ट्रांज़ैक्शन और एक समर्पित रिपॉज़िटरी के साथ करें।

9 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

SQLite आपकी प्रोसेस के भीतर चलता है: कोई सर्वर नहीं, कोई नेटवर्क नहीं, प्रति-क्वेरी विलंब एक माइक्रोसेकंड के क्रम का। यही वह बात है जो better-sqlite3 की तुल्यकालिक (synchronous) API को न केवल स्वीकार्य बनाती है बल्कि अक्सर किसी अतुल्यकालिक ड्राइवर से तेज़ भी: एक टिक से छोटी रीड पर एक प्रॉमिस और एक इवेंट-लूप चक्र की कीमत चुकाने का कोई मतलब नहीं। समझौता राइट पर वास्तविक है: एक धीमी क्वेरी लूप को अवरुद्ध कर देती है। अपनी क्वेरी को इंडेक्स्ड और छोटा रखें, और SQLite प्रति सेकंड हज़ारों रीड संभाल लेता है।

BASH
npm install better-sqlite3
नेटिव मॉड्यूल: ज़रूरत पड़ने पर यह इंस्टॉल के समय कंपाइल होता है।

डेटाबेस खोलते समय, दो सेटिंग्स अंतर पैदा करती हैं। WAL मोड (write-ahead logging) पूरी फ़ाइल को लॉक करने के बजाय एक राइट के दौरान रीड की अनुमति देता है। और स्कीमा को CREATE TABLE IF NOT EXISTS के साथ आइडेम्पोटेंट ढंग से लागू किया जाता है - किसी वास्तविक माइग्रेशन टूल को अपनाने से पहले यह पर्याप्त से अधिक है।

JAVASCRIPT
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;
}
connection.js: खोलना, सेटिंग्स, आइडेम्पोटेंट स्कीमा।

डेटा एक्सेस परत - यानी रिपॉज़िटरी - एकमात्र मॉड्यूल है जो SQL बोलता है। क्वेरी निर्माण के समय एक बार प्रिपेयर की जाती हैं और फिर हर कॉल पर पुनः प्रयोग की जाती हैं: इंजन SQL टेक्स्ट को दोबारा पार्स नहीं करता, और वैल्यू प्लेसहोल्डर ? के ज़रिए गुज़रती हैं, कभी कॉन्कैटेनेशन के ज़रिए नहीं। यह ठीक वही findAll, findByEmail, insert इंटरफ़ेस है जिसकी पिछले पाठ की सर्विस अपेक्षा करती है।

JAVASCRIPT
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();
    },
  };
}
एक बार प्रिपेयर, हज़ार बार निष्पादित: run, get, all।
JAVASCRIPT
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: या तो सब कुछ कमिट होता है, या सब कुछ रोलबैक होता है।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. Node में better-sqlite3 की तुल्यकालिक API एक विरोधाभास क्यों नहीं है?
    • क्योंकि Node नेटिव मॉड्यूल को एक अलग थ्रेड में चलाता है
    • क्योंकि SQLite इन-प्रोसेस है: क्वेरी की कीमत उस अतुल्यकालिक व्यवस्था से कम है जिससे यह वैसे बचती है
    • क्योंकि राइट अपने आप कतार में लगा दी जाती हैं
    • क्योंकि WAL मोड हर क्वेरी को गैर-अवरोधक बना देता है
  2. किसी प्रिपेयर्ड स्टेटमेंट में ? प्लेसहोल्डर क्या सुनिश्चित करते हैं?
    • वैल्यू SQL से अलग पास की जाती हैं और उन्हें कभी कोड के रूप में निष्पादित नहीं किया जा सकता
    • वैल्यू संग्रहीत करने से पहले एन्क्रिप्ट की जाती हैं
    • क्वेरी अपने आप डिस्क पर कैश की जाती है
  3. हज़ार इंसर्ट के लिए db.transaction क्या दोहरा लाभ लाता है?
    • डेटा संपीड़न और स्वतः डुप्लीकेट-हटाव
    • परमाणुता (सब कुछ या कुछ नहीं) और हज़ार के बजाय एक अकेला डिस्क सिंक
    • स्कीमा सत्यापन और लुप्त इंडेक्स का निर्माण