ข้ามไปเนื้อหาหลัก

Category: reference

SQLite สำหรับ Web Developer — ใช้ได้ทั้ง local และ edge

คู่มือใช้ SQLite ใน Node.js, Cloudflare Workers (D1) และ LibSQL — database ที่ไม่ต้องการ server

· อ่านประมาณ 1 นาที

สารบัญ

ทำไม SQLite ถึงเหมาะกับ Personal Projects

  • ไม่ต้องการ server — เป็นแค่ไฟล์ .db
  • เร็วมากสำหรับ read-heavy workload — query ส่วนใหญ่เร็วกว่า Postgres ถ้า dataset ไม่ใหญ่มาก
  • Zero configuration — deploy ได้เลยพร้อม app
  • ใช้ได้บน edge — Cloudflare D1, Turso (LibSQL)

Node.js — better-sqlite3

npm install better-sqlite3
import Database from 'better-sqlite3';
const db = new Database('./data.db');

// สร้าง table
db.exec(`CREATE TABLE IF NOT EXISTS notes (
  id    INTEGER PRIMARY KEY AUTOINCREMENT,
  title TEXT NOT NULL,
  body  TEXT,
  date  TEXT DEFAULT (date('now'))
)`);

// Insert
const insert = db.prepare('INSERT INTO notes (title, body) VALUES (?, ?)');
const result = insert.run('My Note', 'Note content here');
console.log(result.lastInsertRowid);

// Query
const notes = db.prepare('SELECT * FROM notes ORDER BY date DESC').all();
const note  = db.prepare('SELECT * FROM notes WHERE id = ?').get(1);

// Transaction
const addMany = db.transaction((items) => {
  const stmt = db.prepare('INSERT INTO notes (title) VALUES (?)');
  for (const item of items) stmt.run(item);
});
addMany(['Note A', 'Note B', 'Note C']);

Cloudflare D1 (SQLite บน Edge)

// wrangler.toml
// [[d1_databases]]
// binding = "DB"
// database_name = "my-db"

export default {
  async fetch(request, env) {
    const results = await env.DB.prepare(
      'SELECT * FROM notes WHERE id = ?'
    ).bind(1).all();
    return Response.json(results);
  }
};

Drizzle ORM — type-safe SQL

npm install drizzle-orm better-sqlite3
npm install -D drizzle-kit @types/better-sqlite3
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
import { drizzle } from 'drizzle-orm/better-sqlite3';

const notes = sqliteTable('notes', {
  id:    integer('id').primaryKey({ autoIncrement: true }),
  title: text('title').notNull(),
  date:  text('date').default(sql`(date('now'))`),
});

const db = drizzle(sqliteDb);
const allNotes = await db.select().from(notes).orderBy(desc(notes.date));

เมื่อไหร่ไม่ควรใช้ SQLite

  • มีหลาย process เขียนพร้อมกัน (WAL mode ช่วยบ้างแต่ไม่สมบูรณ์)
  • Dataset ขนาดใหญ่มาก (หลาย GB ขึ้นไป) ที่ต้องการ concurrent reads สูง
  • ต้องการ full-text search ขั้นสูง (ใช้ FTS5 extension ได้แต่จำกัด)