Bun 原生實作一個高性能的 SQLite3 驅動程式。若要使用它,請從內建的 bun:sqlite
模組匯入。
import { Database } from "bun:sqlite";
const db = new Database(":memory:");
const query = db.query("select 'Hello world' as message;");
query.get(); // => { message: "Hello world" }
API 簡單、同步且快速。感謝 better-sqlite3 及其貢獻者,啟發了 bun:sqlite
的 API。
功能包括
- 交易
- 參數(命名和位置)
- 準備好的陳述
- 資料類型轉換(
BLOB
變成Uint8Array
) - 所有 JavaScript SQLite 驅動程式中最快
bun:sqlite
模組對於讀取查詢而言,比 better-sqlite3
快約 3-6 倍,比 deno.land/x/sqlite
快約 8-9 倍。每個驅動程式都針對 Northwind Traders 資料集進行基準測試。檢視並執行 基準測試來源。

資料庫
若要開啟或建立 SQLite3 資料庫
import { Database } from "bun:sqlite";
const db = new Database("mydb.sqlite");
若要開啟記憶體中資料庫
import { Database } from "bun:sqlite";
// all of these do the same thing
const db = new Database(":memory:");
const db = new Database();
const db = new Database("");
若要在 readonly
模式中開啟
import { Database } from "bun:sqlite";
const db = new Database("mydb.sqlite", { readonly: true });
如果檔案不存在,則建立資料庫
import { Database } from "bun:sqlite";
const db = new Database("mydb.sqlite", { create: true });
透過 ES 模組載入
您也可以使用 import 屬性來載入資料庫。
import db from "./mydb.sqlite" with { "type": "sqlite" };
console.log(db.query("select * from users LIMIT 1").get());
這相當於下列內容
import { Database } from "bun:sqlite";
const db = new Database("./mydb.sqlite");
.close(throwOnError: boolean = false)
若要關閉資料庫連線,但允許現有查詢完成,請呼叫 .close(false)
const db = new Database();
// ... do stuff
db.close(false);
若要關閉資料庫,並在有任何待處理查詢時擲回錯誤,請呼叫 .close(true)
const db = new Database();
// ... do stuff
db.close(true);
注意:close(false)
會在資料庫被垃圾回收時自動呼叫。可以安全地呼叫多次,但第一次之後就不會再有效果。
using
陳述式
您可以使用 using
陳述式,以確保在退出 using
區塊時關閉資料庫連線。
import { Database } from "bun:sqlite";
{
using db = new Database("mydb.sqlite");
using query = db.query("select 'Hello world' as message;");
console.log(query.get()); // => { message: "Hello world" }
}
.serialize()
bun:sqlite
支援 SQLite 內建的機制,用於將資料庫 序列化 和 反序列化 至記憶體中。
const olddb = new Database("mydb.sqlite");
const contents = olddb.serialize(); // => Uint8Array
const newdb = Database.deserialize(contents);
在內部,.serialize()
會呼叫 sqlite3_serialize
。
.query()
在您的 Database
執行個體上使用 db.query()
方法,以 準備 SQL 查詢。結果是一個 Statement
執行個體,它將快取在 Database
執行個體上。查詢不會執行。
const query = db.query(`select "Hello world" as message`);
注意 — 使用 .prepare()
方法準備查詢,不將其快取在 Database
執行個體上。
// compile the prepared statement
const query = db.prepare("SELECT * FROM foo WHERE bar = ?");
WAL 模式
SQLite 支援 寫入前置記錄模式 (WAL),這可以大幅提升效能,特別是在有許多同時寫入的情況下。對於大多數典型應用程式,建議啟用 WAL 模式。
若要啟用 WAL 模式,請在應用程式開始時執行此 pragma 查詢
db.exec("PRAGMA journal_mode = WAL;");
什麼是 WAL 模式
陳述式
Statement
是一種已準備好的查詢,表示它已剖析並編譯成有效率的二進位格式。它可以在效能良好的情況下執行多次。
使用 Database
執行個體上的 .query
方法來建立陳述式。
const query = db.query(`select "Hello world" as message`);
查詢可以包含參數。這些參數可以是數字 (?1
) 或命名 ($param
或 :param
或 @param
)。
const query = db.query(`SELECT ?1, ?2;`);
const query = db.query(`SELECT $param1, $param2;`);
執行查詢時,值會繫結到這些參數。Statement
可以使用多種不同的方法執行,每種方法都會以不同的形式傳回結果。
.all()
使用 .all()
來執行查詢,並將結果作為物件陣列傳回。
const query = db.query(`select $message;`);
query.all({ $message: "Hello world" });
// => [{ message: "Hello world" }]
在內部,這會呼叫 sqlite3_reset
並重複呼叫 sqlite3_step
,直到它傳回 SQLITE_DONE
。
.get()
使用 .get()
來執行查詢,並將第一個結果作為物件傳回。
const query = db.query(`select $message;`);
query.get({ $message: "Hello world" });
// => { $message: "Hello world" }
在內部,這會呼叫 sqlite3_reset
,然後呼叫 sqlite3_step
,直到它不再傳回 SQLITE_ROW
。如果查詢沒有傳回任何列,則會傳回 undefined
。
.run()
使用 .run()
來執行查詢,並傳回 undefined
。這對於修改架構的查詢 (例如 CREATE TABLE
) 或大量寫入作業很有用。
const query = db.query(`create table foo;`);
query.run();
// => undefined
在內部,這會呼叫 sqlite3_reset
並呼叫 sqlite3_step
一次。當您不關心結果時,不需要逐步執行所有列。
.values()
使用 values()
來執行查詢,並將所有結果作為陣列的陣列傳回。
const query = db.query(`select $message;`);
query.values({ $message: "Hello world" });
query.values(2);
// [
// [ "Iron Man", 2008 ],
// [ "The Avengers", 2012 ],
// [ "Ant-Man: Quantumania", 2023 ],
// ]
在內部,這會呼叫 sqlite3_reset
並重複呼叫 sqlite3_step
,直到它傳回 SQLITE_DONE
。
.finalize()
使用 .finalize()
來銷毀 Statement
並釋放與之相關聯的任何資源。一旦完成,Statement
就無法再次執行。通常,垃圾回收器會為您執行此操作,但在效能敏感的應用程式中,明確完成可能很有用。
const query = db.query("SELECT title, year FROM movies");
const movies = query.all();
query.finalize();
.toString()
對 Statement
執行個體呼叫 toString()
會列印擴充的 SQL 查詢。這對於除錯很有用。
import { Database } from "bun:sqlite";
// setup
const query = db.query("SELECT $param;");
console.log(query.toString()); // => "SELECT NULL"
query.run(42);
console.log(query.toString()); // => "SELECT 42"
query.run(365);
console.log(query.toString()); // => "SELECT 365"
在內部,這會呼叫 sqlite3_expanded_sql
。參數使用最近繫結的值進行擴充。
參數
查詢可以包含參數。它們可以是數字 (?1
) 或命名 ($param
或 :param
或 @param
)。在執行查詢時將繫結值繫結到這些參數
const query = db.query("SELECT * FROM foo WHERE bar = $bar");
const results = query.all({
$bar: "bar",
});
[
{ "$bar": "bar" }
]
編號 (位置) 參數也適用
const query = db.query("SELECT ?1, ?2");
const results = query.all("hello", "goodbye");
[
{
"?1": "hello",
"?2": "goodbye"
}
]
交易
交易是一種以原子方式執行多個查詢的機制;也就是說,所有查詢都成功或都不成功。使用 db.transaction()
方法建立交易
const insertCat = db.prepare("INSERT INTO cats (name) VALUES ($name)");
const insertCats = db.transaction(cats => {
for (const cat of cats) insertCat.run(cat);
});
在此階段,我們尚未插入任何貓!呼叫 db.transaction()
會傳回一個新函數 (insertCats
),它包裝執行查詢的函數。
要執行交易,請呼叫此函數。所有參數都將傳遞到包裝函數;包裝函數的傳回值將由交易函數傳回。包裝函數還可以存取在執行交易的地方定義的 this
內容。
const insert = db.prepare("INSERT INTO cats (name) VALUES ($name)");
const insertCats = db.transaction(cats => {
for (const cat of cats) insert.run(cat);
return cats.length;
});
const count = insertCats([
{ $name: "Keanu" },
{ $name: "Salem" },
{ $name: "Crookshanks" },
]);
console.log(`Inserted ${count} cats`);
當呼叫 insertCats
時,驅動程式會自動開始
一筆交易,並在包裝函數傳回時提交
它。如果擲回例外狀況,交易將會回滾。例外狀況會像平常一樣傳播;它不會被捕獲。
巢狀交易 — 交易函數可以從其他交易函數內部呼叫。這樣做時,內部交易會變成儲存點。
檢視巢狀交易範例
交易也附帶有 deferred
、immediate
和 exclusive
版本。
insertCats(cats); // uses "BEGIN"
insertCats.deferred(cats); // uses "BEGIN DEFERRED"
insertCats.immediate(cats); // uses "BEGIN IMMEDIATE"
insertCats.exclusive(cats); // uses "BEGIN EXCLUSIVE"
.loadExtension()
若要載入 SQLite 擴充功能,請在 Database
執行個體上呼叫 .loadExtension(name)
import { Database } from "bun:sqlite";
const db = new Database();
db.loadExtension("myext");
對於 macOS 使用者
.fileControl(cmd: number, value: any)
若要使用進階 sqlite3_file_control
API,請在 Database
執行個體上呼叫 .fileControl(cmd, value)
。
import { Database, constants } from "bun:sqlite";
const db = new Database();
// Ensure WAL mode is NOT persistent
// this prevents wal files from lingering after the database is closed
db.fileControl(constants.SQLITE_FCNTL_PERSIST_WAL, 0);
value
可以是
數字
TypedArray
undefined
或null
參考
class Database {
constructor(
filename: string,
options?:
| number
| {
readonly?: boolean;
create?: boolean;
readwrite?: boolean;
},
);
query<Params, ReturnType>(sql: string): Statement<Params, ReturnType>;
}
class Statement<Params, ReturnType> {
all(params: Params): ReturnType[];
get(params: Params): ReturnType | undefined;
run(params: Params): void;
values(params: Params): unknown[][];
finalize(): void; // destroy statement and clean up resources
toString(): string; // serialize to SQL
columnNames: string[]; // the column names of the result set
paramsCount: number; // the number of parameters expected by the statement
native: any; // the native object representing the statement
}
type SQLQueryBindings =
| string
| bigint
| TypedArray
| number
| boolean
| null
| Record<string, string | bigint | TypedArray | number | boolean | null>;
資料類型
JavaScript 類型 | SQLite 類型 |
---|---|
字串 | TEXT |
數字 | INTEGER 或 DECIMAL |
布林 | INTEGER (1 或 0) |
Uint8Array | BLOB |
Buffer | BLOB |
bigint | INTEGER |
null | NULL |