mcpField
B
bun-sqlite

bun-sqlite

github.com/secondsky数据与数据库240499 次安装5 周前更新
代码仓库

关于 bun-sqlite

介绍 Bun 内置 SQLite 驱动 `bun:sqlite` 的开发指南,适合在 Bun 中使用 SQLite 的开发者,涵盖数据库访问、查询、事务和性能设置。

主要功能

  1. 01文件与内存数据库
  2. 02预编译语句和参数绑定
  3. 03事务与批量操作
  4. 04SQLite 类型与错误处理
  5. 05WAL 和性能设置

适用场景

  1. 01在 Bun 中打开 SQLite 数据库
  2. 02执行参数化查询
  3. 03用事务组织写入操作
  4. 04调整 SQLite 并发与性能

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/secondsky/claude-skills --skill bun-sqlite

安装后在 Claude Code 中输入/bun-sqlite确认已加载。

详细介绍

Bun SQLite

Bun 通过 bun:sqlite 内置了高性能 SQLite 驱动。

快速入门

import { Database } from "bun:sqlite";

// Create/open database
const db = new Database("mydb.sqlite");

// Create table
db.run(`
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE
  )
`);

// Insert data
db.run("INSERT INTO users (name, email) VALUES (?, ?)", ["Alice", "[email protected]"]);

// Query data
const users = db.query("SELECT * FROM users").all();
console.log(users);

// Close
db.close();

打开数据库

import { Database } from "bun:sqlite";

// File-based database
const db = new Database("data.sqlite");

// In-memory database
const memDb = new Database(":memory:");

// Read-only mode
const readDb = new Database("data.sqlite", { readonly: true });

// Create if not exists (default)
const createDb = new Database("new.sqlite", { create: true });

// Strict mode (recommended)
const strictDb = new Database("strict.sqlite", { strict: true });

运行查询

直接执行
// Run (for INSERT, UPDATE, DELETE, DDL)
db.run("CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)");
db.run("INSERT INTO items (name) VALUES (?)", ["Item 1"]);
db.run("DELETE FROM items WHERE id = ?", [1]);

// Get changes info
const result = db.run("DELETE FROM items WHERE id > ?", [10]);
console.log(result.changes); // Rows affected
console.log(result.lastInsertRowid); // Last inserted ID
预处理语句(推荐)
// Create prepared statement
const stmt = db.prepare("SELECT * FROM users WHERE id = ?");

// Get single row
const user = stmt.get(1);

// Get all rows
const allUsers = db.prepare("SELECT * FROM users").all();

// Get values as array
const values = db.prepare("SELECT name, email FROM users").values();
// [[name1, email1], [name2, email2], ...]

// Iterate with for...of
const iter = db.prepare("SELECT * FROM users");
for (const user of iter.iterate()) {
  console.log(user);
}

参数

位置参数
const stmt = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
stmt.run("Bob", "[email protected]");

// Or as array
stmt.run(["Charlie", "[email protected]"]);
命名参数
const stmt = db.prepare("INSERT INTO users (name, email) VALUES ($name, $email)");
stmt.run({ $name: "Dave", $email: "[email protected]" });

// Also works with : and @
const stmt2 = db.prepare("SELECT * FROM users WHERE name = :name");
stmt2.get({ name: "Dave" }); // Note: no colon in object key

查询方法

const stmt = db.prepare("SELECT * FROM users WHERE active = ?");

// .get() - First row or null
const first = stmt.get(true);

// .all() - All rows as array
const all = stmt.all(true);

// .values() - Rows as arrays (not objects)
const values = stmt.values(true);
// [[1, "Alice", true], [2, "Bob", true]]

// .iterate() - Iterator for memory efficiency
for (const row of stmt.iterate(true)) {
  processRow(row);
}

// .run() - Execute without returning data
db.prepare("DELETE FROM cache WHERE expires < ?").run(Date.now());

事务

// Simple transaction
const insertMany = db.transaction((users: { name: string; email: string }[]) => {
  const insert = db.prepare("INSERT INTO users (name, email) VALUES ($name, $email)");
  for (const user of users) {
    insert.run(user);
  }
  return users.length;
});

const count = insertMany([
  { name: "User1", email: "[email protected]" },
  { name: "User2", email: "[email protected]" },
]);

// Transaction modes
const tx = db.transaction(() => {
  db.run('INSERT INTO users (name, email) VALUES (?, ?)', ['Alice', '[email protected]']);
  db.run('UPDATE accounts SET balance = balance - 100 WHERE user_id = ?', [1]);
});

tx.deferred();   // Default: defer lock until first write
tx.immediate();  // Lock immediately on transaction start
tx.exclusive();  // Exclusive lock, blocks all other connections

批量操作

// WAL mode for better concurrent performance
db.run("PRAGMA journal_mode = WAL");

// Bulk insert with transaction
const insertBulk = db.transaction((items: string[]) => {
  const stmt = db.prepare("INSERT INTO items (name) VALUES (?)");
  for (const item of items) {
    stmt.run(item);
  }
});

insertBulk(["A", "B", "C", "D", "E"]);

列类型

// SQLite types map to JavaScript
/*
  SQLite      JavaScript
  ------      ----------
  INTEGER     number | bigint
  REAL        number
  TEXT        string
  BLOB        Uint8Array
  NULL        null
*/

// Handle BigInt for large integers
const bigStmt = db.prepare("SELECT COUNT(*) as count FROM users");
const result = bigStmt.get();
// result.count may be bigint if > Number.MAX_SAFE_INTEGER

// Store/retrieve Uint8Array
db.run("INSERT INTO files (data) VALUES (?)", [new Uint8Array([1, 2, 3])]);
const file = db.prepare("SELECT data FROM files WHERE id = ?").get(1);
// file.data is Uint8Array

列定义

// Get column info
const stmt = db.prepare("SELECT * FROM users");
const columns = stmt.columnNames;
// ["id", "name", "email"]

// Type annotations (Bun extension)
const typedStmt = db.prepare<{ id: number; name: string }, [number]>(
  "SELECT id, name FROM users WHERE id = ?"
);
const user = typedStmt.get(1);
// user is typed as { id: number; name: string } | null

错误处理

import { Database, SQLiteError } from "bun:sqlite";

try {
  db.run("INSERT INTO users (email) VALUES (?)", ["[email protected]"]);
} catch (error) {
  if (error instanceof SQLiteError) {
    console.error("SQLite error:", error.code, error.message);
    // error.code: "SQLITE_CONSTRAINT_UNIQUE"
  }
  throw error;
}

数据库管理

// Close database
db.close();

// Check if open
console.log(db.inTransaction); // Is in transaction

// Serialize to buffer
const buffer = db.serialize();
await Bun.write("backup.sqlite", buffer);

// Load from buffer
const data = await Bun.file("backup.sqlite").arrayBuffer();
const restored = Database.deserialize(data);

// Filename
console.log(db.filename); // Path or ":memory:"

常见模式

仓库模式
import { Database } from "bun:sqlite";

interface User {
  id: number;
  name: string;
  email: string;
}

class UserRepository {
  private db: Database;
  private stmts: {
    findById: ReturnType<Database["prepare"]>;
    findAll: ReturnType<Database["prepare"]>;
    create: ReturnType<Database["prepare"]>;
    update: ReturnType<Database["prepare"]>;
    delete: ReturnType<Database["prepare"]>;
  };

  constructor(db: Database) {
    this.db = db;
    this.stmts = {
      findById: db.prepare("SELECT * FROM users WHERE id = ?"),
      findAll: db.prepare("SELECT * FROM users"),
      create: db.prepare("INSERT INTO users (name, email) VALUES ($name, $email)"),
      update: db.prepare("UPDATE users SET name = $name, email = $email WHERE id = $id"),
      delete: db.prepare("DELETE FROM users WHERE id = ?"),
    };
  }

  findById(id: number): User | null {
    return this.stmts.findById.get(id) as User | null;
  }

  findAll(): User[] {
    return this.stmts.findAll.all() as User[];
  }

  create(user: Omit<User, "id">): number {
    const result = this.stmts.create.run(user);
    return Number(result.lastInsertRowid);
  }
}

常见错误

错误原因解决方法
SQLITE_CONSTRAINT约束冲突检查 UNIQUE/FK 约束
SQLITE_BUSY数据库已锁定使用 WAL 模式,添加重试逻辑
no such table表不存在先运行 CREATE TABLE
database is locked并发访问启用 WAL 模式

性能提示

-- Enable WAL mode (better concurrency)
PRAGMA journal_mode = WAL;

-- Faster writes (less durable)
PRAGMA synchronous = NORMAL;

-- Increase cache size
PRAGMA cache_size = 10000;

-- Enable foreign keys
PRAGMA foreign_keys = ON;

何时加载参考资料

在以下情况下加载 references/pragmas.md:

  • 性能调优
  • 日志模式
  • 内存配置

在以下情况下加载 references/fts.md:

  • 全文搜索
  • FTS5 配置

评论

支持 Markdown