2026/9/12 16:22:08

使用 Turso Database for JavaScript:进程内 SQLite 兼容数据库的安装、查询、事务与 WebAssembly 实践

使用 Turso Database for JavaScript:进程内 SQLite 兼容数据库的安装、查询、事务与 WebAssembly 实践 使用 Turso Database for JavaScript进程内 SQLite 兼容数据库的安装、查询、事务与 WebAssembly 实践【免费下载链接】tursoA SQL database in Rust: SQLite-compatible, now also speaking Postgres (experimental). The LLVM of databases.项目地址: https://gitcode.com/GitHub_Trending/tu/tursotursodatabase/database是 Turso 官方提供的 JavaScript 数据库绑定库它把用 Rust 编写的 SQLite 兼容数据库引擎直接嵌入 Node.js 进程无需网络开销即可创建内存或文件型数据库。读完本文你将掌握该包的安装方式、内存/文件数据库的建表与增删改查、基于transactionAsync的原子事务、batch批量执行、查询超时控制、连接选项含加密与实验特性以及浏览器 WebAssembly 用法并了解其底层异步步进执行模型。一、Turso Database for JavaScript 是什么tursodatabase/database是 Turso 的进程内in-processJavaScript 数据库库。与需要连接远程服务的驱动不同它把数据库引擎直接加载进你的 Node.js 进程SQL 执行不经过任何网络层。官方 README 列举的核心特性如下SQLite 兼容支持 SQLite 查询语言与文件格式兼容性状态可参考仓库根目录的 COMPAT.md进程内运行零网络开销直接在 Node.js 进程中执行TypeScript 支持内置完整的 TypeScript 类型定义跨平台支持 Linuxx86 与 arm64、macOS、Windows以及通过 WebAssembly 支持浏览器运行。需要说明的是该项目尚未发布 1.0 正式版当前仓库中 package.json 的版本号为0.8.0-pre.10官方明确建议在生产环境保持备份。二、安装与包结构在 Node.js 项目中安装非常简单npm install tursodatabase/database从仓库源码结构看bindings/javascript是一个 npm workspaces 管理的 monorepo见 package.json核心工作区包括packages/commonTypeScript 公共层提供Database/Statement/Transaction的 Promise 式高层 APIpromise.ts以及与 better-sqlite3 风格对齐的兼容 APIcompat.tspackages/native基于 N-API由 NAPI-RS 生成类型声明 index.d.ts的原生绑定直接调用 Rust 引擎packages/wasm与packages/wasm-commonWebAssembly 构建用于浏览器环境sync/packages/...与 Turso Cloud 双向同步相关的三件套common / native / wasm。底层数据库引擎由 Rust 实现见 bindings/javascript/src 与 Cargo.toml通过 N-API 暴露给 JavaScript 层这正是其“进程内、低开销”的来源。三、快速上手内存数据库通过connect(:memory:)即可创建一个完全驻留内存的数据库适合测试、缓存与临时计算场景import { connect } from tursodatabase/database; // Create an in-memory database const db await connect(:memory:); // Create a table await db.exec( CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT) ); // Insert data const insert db.prepare(INSERT INTO users (name, email) VALUES (?, ?)); await insert.run(Alice, aliceexample.com); await insert.run(Bob, bobexample.com); // Query data const users await db.prepare(SELECT * FROM users).all(); console.log(users); // Output: [ // { id: 1, name: Alice, email: aliceexample.com }, // { id: 2, name: Bob, email: bobexample.com } // ]关键点db.exec(sql)可执行包含多条 SQL 语句的字符串源码中exec通过executor逐步驱动执行见 promise.tsdb.prepare(sql)返回预编译的Statement可重复绑定不同参数执行stmt.run(...)返回包含changes与lastInsertRowid的信息对象stmt.all()返回全部行默认每行是形如{ id: 1, name: Alice }的对象。四、文件型数据库传入一个文件路径即可创建或打开磁盘数据库。文件不存在时会自动创建见 docs/API.mdimport { connect } from tursodatabase/database; // Create or open a database file const db await connect(my-database.db); // Create a table await db.exec( CREATE TABLE IF NOT EXISTS posts ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ); // Insert a post const insertPost db.prepare(INSERT INTO posts (title, content) VALUES (?, ?)); const result await insertPost.run(Hello World, This is my first blog post!); console.log(Inserted post with ID: ${result.lastInsertRowid});通过result.lastInsertRowid可以拿到自增主键 ID。此外connect还支持查询db.path、db.memory、db.readonly、db.open等属性见 index.d.ts便于运行时判断数据库状态。五、事务transactionAsync 的正确用法官方推荐用db.transactionAsync(fn)包装事务逻辑回调的第一个参数是一个Transaction句柄后续参数是调用包装函数时传入的参数import { connect } from tursodatabase/database; const db await connect(transactions.db); // Using transactions for atomic operations const transaction db.transactionAsync(async (txn, users) { const insert await txn.prepare(INSERT INTO users (name, email) VALUES (?, ?)); for (const user of users) { await insert.run(user.name, user.email); } }); // Execute transaction await transaction([ { name: Alice, email: aliceexample.com }, { name: Bob, email: bobexample.com } ]);从 promise.ts 的实现看transactionAsync有几个重要行为包装器独占连接在发出BEGIN之前获取数据库的执行锁execLock直到COMMIT/ROLLBACK之后才释放期间其他语句/事务无法插入到该事务窗口内回调内 SQL 必须走Transaction句柄若回调内直接调用db或数据库预编译的语句会因为等待本事务持有的锁而死锁assertTransactionCallbackpromise.ts会拒绝未声明句柄参数的回调如fn.length 0的旧式签名自动回滚回调抛出异常时自动执行ROLLBACK成功后执行COMMIT事务模式包装函数暴露default、deferred、concurrent、immediate、exclusive五个模式属性分别对应不同的BEGIN锁定模式await transaction.immediate([ { name: Alice, email: aliceexample.com }, ]);六、批量执行batch 与原子批处理db.batch(statements, options)按顺序执行一组语句返回与 libSQL 客户端一致的ResultSet数组每个结果含columns、columnTypes、rows、rowsAffected插入语句还带lastInsertRowid// 纯 SQL 字符串默认非原子每条语句独立自动提交 await db.batch([ INSERT INTO users(name) VALUES (Alice), INSERT INTO users(name) VALUES (Bob), ]); // 支持位置参数 ? 与命名参数 :name await db.batch([ { sql: INSERT INTO users(name, email) VALUES (?, ?), args: [Carol, carolexample.net] }, { sql: INSERT INTO users(name, email) VALUES (:name, :email), args: { name: Dave, email: daveexample.net } }, ]); // 通过 mode 参数实现原子批处理整体包在 BEGIN IMMEDIATE / COMMIT 中失败自动 ROLLBACK await db.batch([ { sql: INSERT INTO users(name) VALUES (?), args: [Eve] }, { sql: INSERT INTO users(name) VALUES (?), args: [Frank] }, ], immediate);mode的取值映射见 promise.ts 的normalizeBatchModemode 值实际 SQL 模式write/immediateBEGIN IMMEDIATEread/deferredBEGIN DEFERREDexclusiveBEGIN EXCLUSIVEconcurrentBEGIN CONCURRENT需要留意两点一是原子模式下批处理内的语句不允许包含BEGIN、COMMIT、END、ROLLBACK、SAVEPOINT、RELEASE等事务控制关键字会在执行前被拒绝二是当语句失败时抛出的错误携带batchIndex失败语句的零基下标与batchResults每条语句一个结果失败及未执行的为null方便定位问题。七、查询超时timeout、defaultQueryTimeout 与 queryOptions数据库引擎默认提供三类时间相关选项定义见 types.tstimeoutbusy timeout单位毫秒用于等待锁释放defaultQueryTimeout默认的查询执行超时毫秒超时后中断执行queryOptions.queryTimeout单次查询级别的超时覆盖优先级最高例如await db.exec(SELECT 1, { queryTimeout: 100 }); const stmt await db.prepare(SELECT * FROM big_table); await stmt.get(undefined, { queryTimeout: 100 });Statement上也提供setQueryTimeout(queryOptions)方法见 index.d.ts可以在准备语句后单独设置超时。八、连接选项 DatabaseOpts 详解connect(path, options)的第二个参数支持以下字段完整定义见 types.ts选项类型说明readonlyboolean以只读模式打开数据库fileMustExistboolean文件必须存在否则报错timeoutnumberbusy timeout毫秒defaultQueryTimeoutnumber默认查询超时毫秒tracinginfo \| debug \| trace追踪日志级别experimentalExperimentalFeature[]启用实验特性encryptionEncryptionOpts本地数据库加密配置实验特性列表来自源码 types.tsviews、strict、encryption、index_method、custom_types、autovacuum、vacuum、triggers、attach、generated_columns、multiprocess_wal、without_rowid。用法示例const db await connect(app.db, { experimental: [views, triggers], });本地加密encryption需要指定cipher与hexkey十六进制编码的密钥。支持的加密算法见 types.ts包括aes128gcm、aes256gcm、aegis256、aegis256x2、aegis128l、aegis128x2、aegis128x4const db await connect(encrypted.db, { encryption: { cipher: aes256gcm, hexkey: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef, }, });九、Statement APIrun / get / all / iterate 与行展示模式预编译语句Statement提供四种执行方式stmt.run(...)执行写操作返回{ changes, lastInsertRowid }stmt.get(...)返回第一行无匹配时返回undefinedstmt.all(...)返回全部行组成的数组stmt.iterate(...)返回异步迭代器逐行消费适合大结果集。Database上也提供了同名便捷方法db.run、db.get、db.all、db.iterate内部自动 prepare 并在调用返回前 finalize见 promise.ts。文档 docs/API.md 明确标注run、get、all、iterate是 libSQL 的扩展 APIbetter-sqlite3 中没有对应实现。行展示模式与 better-sqlite3 对齐stmt.raw(true)返回数组而非对象raw()不带参默认开启raw(false)关闭stmt.pluck(true)只返回第一列的值pluck()不带参默认开启safeIntegers(true)/db.defaultSafeIntegers(true)以 BigInt 安全返回 64 位整数SQLite 的整数超出 JSNumber安全范围时很有用。注意raw与pluck是互斥选项见 docs/API.md 中对pluck、raw的说明。此外Statement还提供parameterCount()、parameterName(index)1 起始下标、columns()返回列名与类型等反射方法以及reset()与finalize()生命周期管理。十、浏览器与 WebAssembly 支持README 提到浏览器可通过 WebAssembly 运行。仓库中对应实现位于packages/wasm含 worker.ts、wasm-inline.ts 以及针对 Vite、Turbopack 的入口适配packages/wasm-common提供跨构建的公共逻辑。从 promise.ts 的io()实现注释可以看到浏览器与 Node.js 的差异浏览器 WASM 构建中I/O 由 OPFS Worker 异步完成ioStep等待 I/O 通知器解析的 Promise而内存/Node.js 构建中 I/O 是同步的ioStep为空操作。这正是“同一套 API双端运行”的架构基础。十一、底层原理异步步进执行模型理解执行模型有助于写出高效代码。绑定层不采用“一条 SQL 同步跑完”的模式而是把每条语句拆成步进循环step loop每次stepSync()返回[step, sleepMs]二元组其中step取值为常量定义见 types.tsSTEP_ROW1取到一行数据STEP_DONE2语句执行完毕STEP_IO3引擎需要等待异步 I/O 完成驱动层调用io()挂起等待STEP_SLEEP4引擎要求延迟sleepMs毫秒后重试如 busy-handler 退避驱动层用定时器setTimeout等待后继续。db.exec的实现promise.ts就是围绕这套步进常量的循环遇到STEP_IO就 await I/O遇到STEP_SLEEP就sleepBeforeRetry(sleepMs)遇到STEP_DONE结束。同时同一连接上的所有原生调用都通过AsyncLockexecLock串行化避免并发 step 循环在共享连接上交错执行——这也是transactionAsync必须通过Transaction句柄访问 SQL 的原因见 promise.ts。这套设计使引擎能够实现协作式调度与真正的异步 I/O在浏览器端配合 OPFS Worker 不阻塞主线程在 Node.js 端又能以极小开销直接执行。原生层还暴露了classifySql返回read/write/begin/commit/rollback、changes()、totalChanges()、inTransaction()、ioLoopSync()/ioLoopAsync()等底层能力见 index.d.ts。十二、相关生态包与许可官方 README 还推荐了两个同 API 生态的包tursodatabase/serverlesstursodatabase/sync。本文介绍的tursodatabase/database采用 MIT 许可。想进一步了解完整的类与方法签名可阅读仓库内的 API 文档SQLite 兼容性状态见 COMPAT.md绑定层构建与发布脚本可参考 Makefile 与 Cargo.toml。【免费下载链接】tursoA SQL database in Rust: SQLite-compatible, now also speaking Postgres (experimental). The LLVM of databases.项目地址: https://gitcode.com/GitHub_Trending/tu/turso创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考