3.1 安装
npm install @libsql/client
# 或
pnpm add @libsql/client
bun add @libsql/client
包内包含两个入口,自动按运行时选择:
@libsql/client— Node.js(含better-sqlite3原生加速)@libsql/client/web— Cloudflare Workers / Vercel Edge / 浏览器(纯 fetch,无原生依赖)
3.2 第一次连接
import { createClient } from '@libsql/client';
const db = createClient({
url: process.env.TURSO_DATABASE_URL!, // libsql://...turso.io
authToken: process.env.TURSO_AUTH_TOKEN!,
});
const res = await db.execute('SELECT 1 as x');
console.log(res.rows); // [{ x: 1 }]
Edge 运行时
import { createClient } from '@libsql/client/web';
const db = createClient({
url: env.TURSO_DATABASE_URL,
authToken: env.TURSO_AUTH_TOKEN,
});
/web 版仅用 fetch,能在 Cloudflare Workers(无 TCP)、Vercel Edge、Deno Deploy、浏览器中运行。功能集稍窄:不支持嵌入式副本(要文件系统),其他 SQL 操作完全一致。
3.3 execute:运行单条 SQL
// 简单查询
const { rows } = await db.execute('SELECT * FROM users LIMIT 10');
// 参数绑定(位置)
await db.execute({
sql: 'SELECT * FROM users WHERE email = ?',
args: ['alice@example.com'],
});
// 参数绑定(命名)
await db.execute({
sql: 'INSERT INTO users (name, age) VALUES (:name, :age)',
args: { name: 'Alice', age: 30 },
});
不要拼字符串。libSQL 的 ? 和 :name 会做二进制级别的绑定,防 SQL 注入、减少 parse 开销。
3.4 返回结构
interface ResultSet {
columns: string[]; // ['id', 'name']
rows: Row[]; // [{ id:1, name:'A' }, ...]
rowsAffected: number; // UPDATE/DELETE 的行数
lastInsertRowid: bigint; // INSERT 的 rowid(注意是 bigint)
}
lastInsertRowid 在 JS 里是 bigint——JSON.stringify 会抛错,要写成字符串。
3.5 类型映射
| SQLite 列类型 | JS 返回类型 |
|---|---|
| INTEGER(< 2^53) | number |
| INTEGER(更大) | bigint(需 intMode: 'bigint') |
| REAL | number |
| TEXT | string |
| BLOB | Uint8Array |
| NULL | null |
配置整数模式:
const db = createClient({
url, authToken,
intMode: 'bigint', // 全部 int 作为 bigint
// 或 'string'(适合前端 JSON)
});
3.6 批量:batch
一次 RTT 发多条 SQL,全部成功才提交(自动包在事务里):
await db.batch([
'CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)',
{ sql: 'INSERT INTO users (name) VALUES (?)', args: ['Alice'] },
{ sql: 'INSERT INTO users (name) VALUES (?)', args: ['Bob'] },
], 'write'); // 'read' | 'write' | 'deferred'
第二个参数决定事务模式:
'read'——所有语句只读;可以在 replica 上执行'write'——包含写入;强制发 primary'deferred'——延迟决定(SQLite 默认行为)
3.7 交互式事务:transaction
当你需要"先读、再决定是否写"时用交互式事务:
const tx = await db.transaction('write');
try {
const { rows } = await tx.execute('SELECT balance FROM accounts WHERE id=?', [1]);
if (rows[0].balance >= 100) {
await tx.execute('UPDATE accounts SET balance=balance-100 WHERE id=?', [1]);
await tx.execute('UPDATE accounts SET balance=balance+100 WHERE id=?', [2]);
}
await tx.commit();
} catch (e) {
await tx.rollback();
throw e;
}
打开 transaction 后,primary 上的该数据库实际上被你的客户端锁住(读写锁)。用完一定 commit/rollback——忘了的话锁会超时释放(默认 5 秒),期间其他写会被拒。
3.8 连接池?不需要
libSQL 是 HTTP/WebSocket 协议——没有 TCP 连接池的概念。一个 createClient 出来的 client 是可以全局共享的,内部自动管理 HTTP 连接复用。
Edge 环境里:每个请求里 createClient 一次也 OK(开销仅是对象创建),但如果走 module scope 会更好:
// lib/db.ts
import { createClient } from '@libsql/client/web';
export const db = createClient({ url, authToken });
// 各路由直接 import { db } from '@/lib/db'
3.9 错误处理
import { LibsqlError } from '@libsql/client';
try {
await db.execute('INSERT INTO users(email) VALUES(?)', ['a@a.com']);
} catch (e) {
if (e instanceof LibsqlError) {
console.log(e.code); // 'SQLITE_CONSTRAINT_UNIQUE'
console.log(e.rawCode); // SQLite errno
}
}
常见 code:SQLITE_CONSTRAINT_UNIQUE、SQLITE_BUSY、SQLITE_READONLY、HRANA_PROTO_*(协议错误)。
3.10 跨运行时:Node/Bun/Deno/Workers
| 运行时 | 导入路径 | 嵌入式副本 | 备注 |
|---|---|---|---|
| Node.js | @libsql/client | ✅ | best-sqlite3 原生 |
| Bun | @libsql/client | ✅ | bun:ffi 加速 |
| Deno | npm:@libsql/client | ✅ | 需 --unstable-ffi |
| Cloudflare Workers | @libsql/client/web | ❌ | fetch 驱动 |
| Vercel Edge | @libsql/client/web | ❌ | fetch 驱动 |
| 浏览器 | @libsql/client/web | ❌ | CORS 需代理 |
3.11 最小示例:Hono + Turso
import { Hono } from 'hono';
import { createClient } from '@libsql/client/web';
type Env = { Bindings: { TURSO_URL: string; TURSO_TOKEN: string } };
const app = new Hono<Env>();
app.get('/users', async (c) => {
const db = createClient({
url: c.env.TURSO_URL,
authToken: c.env.TURSO_TOKEN,
});
const { rows } = await db.execute('SELECT id, name FROM users');
return c.json(rows);
});
export default app;
小结
libSQL JS SDK 的 4 个核心 API:execute(单条)、batch(多条/事务)、transaction(交互式)、sync(嵌入式副本,下章讲)。区分 Node 版和 /web 版决定了你能不能跑在 Edge。下一章我们挖 Turso 最酷的特性——嵌入式副本。