ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

使用 @tursodatabase/sync 在 JavaScript 中实现 Turso 本地数据库与云端双向同步

使用 @tursodatabase/sync 在 JavaScript 中实现 Turso 本地数据库与云端双向同步 使用 tursodatabase/sync 在 JavaScript 中实现 Turso 本地数据库与云端双向同步【免费下载链接】tursoA SQL database in Rust: SQLite-compatible, now also speaking Postgres (experimental). The LLVM of databases.项目地址: https://gitcode.com/GitHub_Trending/tu/tursoTursoturso是一个用 Rust 编写的 SQLite 兼容数据库而tursodatabase/sync是面向 JavaScript/TypeScript 生态的同步引擎包用于将本地 Turso 数据库与 Turso Cloud 托管数据库进行双向同步。本文以 bindings/javascript/sync/README.md 为主线结合该仓库中 sync 包的 TypeScript 源码sync/packages/common、sync/packages/native、sync/packages/wasm与 NAPI 类型定义完整讲解安装、connect配置、pull/push/sync同步流程、高级选项加密、transform、远程写、部分同步等以及底层同步引擎的运作原理帮助你快速上手并深入理解同步机制。包定位与适用场景tursodatabase/sync的核心职责是将本地 Turso 数据库与 Turso Cloud 之间进行双向同步原文This package is for syncing local Turso databases to the Turso Cloud and back。在 Turso 的 JavaScript 生态中它与其他包的分工如下见 sync/README.md 与 native 包 READMEtursodatabase/database提供内存版 Turso 数据库兼容 SQLite 查询语言与文件格式直接运行在 Node.js 进程内无网络开销tursodatabase/database-wasm浏览器WASM环境的嵌入式数据库库tursodatabase/serverless提供相同 API 的 serverless 驱动tursodatabase/sync在上述本地数据库能力之上增加与云端数据库的双向同步能力。需要注意的是tursodatabase/sync连接的数据库由connect返回的对象与tursodatabase/database包的Database类拥有相同的函数只是额外增加了几个用于同步的方法pull、push、sync这与源码中class Database extends DatabasePromise见 promise.ts的实现一致——同步数据库实例继承自通用的DatabasePromise基类。从仓库状态看Turso 数据库已在多家组织的生产环境中运行但尚未达到 1.0 版本官方在文档中明确建议保持备份。安装在 Node.js 项目中安装同步包npm install tursodatabase/sync从 native 包 package.json 可以看到该包是 NAPI-RS 原生模块二进制名sync并依赖两个配套包tursodatabase/database-common提供DatabasePromise、Transaction等公共基础类tursodatabase/sync-common提供同步引擎协议、runner、retryFetch等公共逻辑。支持的原生目标平台包括x86_64-unknown-linux-gnu、x86_64-pc-windows-msvc、aarch64-apple-darwin、aarch64-unknown-linux-gnu即 Linuxx86/arm64、macOS 与 Windows 均可用。快速开始同步一个 Turso Cloud 数据库以下示例完整来自 sync/README.md 的 Getting Started 章节用于将托管在 Turso Cloud 的数据库同步到本地import { connect } from tursodatabase/sync; const db await connect({ path: local.db, // path used as a prefix for local files created by sync-engine url: https://db.turso.io, // URL of the remote database: turso db show db authToken: ..., // auth token issued from the Turso Cloud: turso db tokens create db clientName: turso-sync-example // arbitrary client name }); // db has same functions as Database class from tursodatabase/database package but adds few more methods for sync: await db.pull(); // pull changes from the remote await db.push(); // push changes to the remote await db.sync(); // pull push changes几点关键解读path是本地文件的路径前缀。正如 types.ts 中DatabaseOpts.path的注释所说明同步数据库会以该前缀写出多个文件例如local.db-info、local.db-wal等不仅仅是单个数据库文件url是远程数据库地址可以通过turso db show db获取注意它同时支持libsql://与https://两种协议前缀——在 run.ts 的normalizeUrl中会把libsql://或turso://统一归一化为https://后再发起请求authToken通过turso db tokens create db签发clientName是任意客户端名称用于在服务端区分客户端源码注释说明库会通过追加唯一后缀来保证clientId的唯一性。创建连接后db同时具备普通数据库能力exec、prepare、transaction等与三个同步方法。sync()等价于先pull()再push()。核心同步 API 详解pull()从远程拉取变更await db.pull(); // 返回 true 表示拉取到了新变更pull()的语义与返回值的细节可从 promise.ts 的实现确认若数据库是以无同步方式打开未提供url调用会抛出sync is disabled as database was opened without sync support内部先调用engine.wait()等待远程产生新变更再调用engine.apply(changes)将变更应用到本地如果拉取到的变更集为空返回false否则应用变更后返回true如果设置了longPollTimeoutMs服务端会保持连接打开直到数据库出现新变更或超时可用于实时监听场景。push()推送本地变更到远程await db.push();push()将本地累积的未同步变更发送到远程见 promise.ts。如果设置了transform回调则每条变更在发送前都会经过该回调处理详见下文 transform 章节。sync()先拉后推await db.sync(); // pull push changessync()是pull()与push()的组合操作适合在程序的关键节点如启动时、写入一批数据后做一次完整的双向同步。checkpoint() 与 stats()除了文档提到的三个同步方法同步数据库还提供了见 promise.tsawait db.checkpoint()对本地数据库执行 WAL checkpointawait db.stats()返回同步引擎统计信息其结构定义在 types.ts 的DatabaseStats字段含义cdcOperations尚未发送到远程的本地变更CDC 操作数量mainWalSize主 WAL 文件大小字节revertWalSize回滚 WAL 文件大小字节lastPullUnixTime最近一次成功 pull 的 Unix 时间戳lastPushUnixTime最近一次成功 push 的 Unix 时间戳可为 nullrevision从远程拉取到的变更的不透明版本号可作为 etag 使用但不应解释其内容networkSentBytes/networkReceivedBytes网络发送/接收的总字节数connect 完整配置项DatabaseOptsconnect接受的配置对象类型为DatabaseOpts完整定义在 types.ts。下表汇总了所有字段及其语义字段类型说明pathstring必填本地文件路径前缀同步引擎会写入多个带此前缀的文件urlstring \| (() string \| null)远程数据库地址。省略时为纯本地数据库也支持传入函数返回非空值时启用同步延迟同步此时其他参数如加密必须预先设置authTokenstring \| (() Promisestring)远程鉴权令牌支持函数形式以按请求提供短期凭证clientNamestring任意客户端名库会附加唯一后缀保证 clientId 唯一remoteEncryptionEncryptionOpts云端数据库加密参数若云端默认加密transformTransform每条变更发送到远程前的回调可用于实现复杂冲突解决策略longPollTimeoutMsnumberpull 操作的长轮询超时时间不设置则无超时tracingerror \| warn \| info \| debug \| trace开启内部日志experimentalExperimentalFeature[]在本地数据库上启用的实验特性如views、index_method、vacuum与普通Database的experimental选项对应remoteWritesExperimentalboolean实验性写语句在远程服务器执行而非本地每次写或事务提交后自动 pull 以保持读写一致性。需要url且所有显式事务都走远程pushOperationsThresholdnumber单个 push HTTP 批次中打包的 CDC 操作数量上限达到后按事务边界拆分单个用户事务不会被拆分。默认不设置一次发送全部变更集pullBytesThresholdnumber引导bootstrap下载拆分为多个/pull-updatesHTTP 请求的字节数提示使用server_pages_selector位图。默认单次往返完成引导仅影响引导阶段增量 pull 不受影响部分同步使用query策略时无效logicalMvccPullboolean增量 pull 的同步协议覆盖默认自动探测远程协议WAL 页流 vs MVCC 逻辑日志流并持久化true强制 MVCC 逻辑日志流false强制页流。通常仅测试或作为逃生舱使用fetchtypeof fetch同步引擎所有 HTTP 请求push、pull、wait-for-changes的 fetch 实现替换可用于重试/退避见retryFetch、AbortSignal 超时、请求日志、测试 mockpartialSyncExperimentalobject实验性部分同步配置见下文url 的延迟同步与动态鉴权url与authToken都支持函数形式见 types.ts这在 promise.ts 中有完整实现当url是函数时本地数据库先创建同步在 url 返回非空值时开启同步引擎每次 HTTP 请求时都会调用该函数获取最新地址见 run.ts若返回 null 则引擎被暂停url is empty - sync is paused当authToken是函数时每次请求都会调用它动态生成Authorization: Bearer token头适合接入短期凭证刷新机制。加密EncryptionOptsremoteEncryption的EncryptionOpts定义在 types.tsinterface EncryptionOpts { // base64 编码的加密密钥根据算法必须是 16 或 32 字节 key: string, // 加密算法 // - aes256gcm, aes128gcm, chacha20poly1305: 预留 28 字节 // - aegis128l, aegis128x2, aegis128x4: 预留 32 字节 // - aegis256, aegis256x2, aegis256x4: 预留 48 字节 cipher: aes256gcm | aes128gcm | chacha20poly1305 | aegis128l | aegis128x2 | aegis128x4 | aegis256 | aegis256x2 | aegis256x4 }当配置了remoteEncryption时promise.ts 会在每次请求中额外附加两个 HTTP 头x-turso-encryption-key与x-turso-encryption-cipher同步引擎的 NAPI 构造参数也相应接受remoteEncryptionCipher与remoteEncryptionKey见 index.d.ts。transform发送前的变更改写transform回调类型为Transform (arg: DatabaseRowMutation) DatabaseRowTransformResulttypes.ts。DatabaseRowMutation描述一条变更interface DatabaseRowMutation { changeTime: number; // 变更的 Unix 秒级时间戳 tableName: string; // 变更所属表名 id: number; // 变更行的 rowid changeType: insert | update | delete; // 变更类型 before?: Recordstring, any; // 变更前的行数据 after?: Recordstring, any; // 变更后的行数据 updates?: Recordstring, any; // 变更中仅被更新的列 }返回值DatabaseRowTransformResult有三种可能源码注释见 types.ts{ operation: skip }完全忽略该变更不发送也不应用{ operation: rewrite, stmt: { sql, values } }用提供的 SQL 语句替换该变更null保持变更原样。底层处理在 run.ts 的Transform请求类型中每条 mutation 的结果被映射为Keep/Skip/Rewrite三种内部指令传给同步引擎。部分同步partialSyncExperimental实验性partialSyncExperimental: { // bootstrap 策略 // - prefix: 启动时先在本地加载前 N 字节 // - query: 加载指定 SQL 语句触及的页面 bootstrapStrategy: { kind: prefix, length: number } | { kind: query, query: string }, // 分段大小让同步引擎按 segment_size 字节分批加载页面 // 例如以 128kb 加载第 1 页时会加载 [1..32] 共 32 页 segmentSize?: number, // 预取可能很快会被访问的页面 prefetch?: boolean, }该配置在 promise.ts 中被转换为 NAPI 层的JsPartialSyncOptsPrefix/Query两种 bootstrap 策略见 index.d.ts后传给同步引擎。底层原理同步引擎与协议循环tursodatabase/sync并非简单地上传/下载整个文件而是由一个 Rust 编写的同步引擎SyncEngine通过 NAPI-RS 暴露见 index.d.ts 的SyncEngine类以生成器generator协议驱动。理解这一点有助于把握connect、pull、push的真实开销与行为。协议循环runner / run同步引擎通过GeneratorHolderconnect()、wait()、push()、apply()、checkpoint()、stats()都返回该对象以resumeAsync方式推进每次推进可能产生四类请求见 index.d.ts 的JsProtocolRequestHttp向远程服务器发起 HTTP 请求方法、路径、请求头、请求体由引擎给出FullRead读取本地元数据文件FullWrite原子写入本地元数据文件Transform把一批 mutation 交给 JS 侧的transform回调处理。这些请求由 run.ts 的process()逐类执行runner()则维护请求队列并推进引擎的 I/O 循环ioLoopAsync。同步引擎的每个 HTTP 请求都会附加上文构造的鉴权/加密头。并发控制SyncEngineGuards由于同步操作会与本地语句执行交错进行run.ts 定义了SyncEngineGuards用四把异步锁waitLock、pushLock、pullLock、checkpointLock串行化关键操作pull()走wait守卫只持 waitLock拉取到变更后再走apply守卫四把锁全持有来应用变更push()走push守卫持 push/pull/checkpoint 三把锁checkpoint()走checkpoint守卫四把锁全持有。这样保证 wait长轮询、push、apply、checkpoint 之间互不重叠避免本地数据库文件状态在同步过程中被并发破坏。原生 I/O 与内存 I/ONode.js 环境下使用NodeIO见 promise.ts通过node:fs/promises读写文件且写入采用先写临时文件再 rename的原子方式${path}.tmp.${unix}.${nonce}避免半写状态若底层数据库是内存模式则改用memoryIO()把元数据保存在Map中run.ts。远程写remoteWritesExperimental开启remoteWritesExperimental后promise.ts 的exec/prepare会先通过classifySqlNAPI 层的Database.classifySql见 index.d.ts判断 SQL 类别read/write/begin/commit/rollback读语句仍在本地执行写语句通过RemoteWriterremote-writer.ts发送到远程RemoteWriter内部复用tursodatabase/serverless的Session每次写或事务提交后自动pull()一次以保证读写一致性read-your-writes事务整体在远程执行BEGIN ...、COMMIT、ROLLBACK由execRemote自动识别并管理会话生命周期见 remote-writer.ts。需要注意transactionAsync目前不支持与remoteWritesExperimental同时使用会抛出明确错误见 promise.ts此时应使用已标记 deprecated 的transaction()。retryFetch弹性网络传输同步引擎的fetch可替换为 run.ts 提供的retryFetch()为所有同步 HTTP 请求增加重试/退避能力重试条件网络错误DNS、连接重置、AbortError 等、5xx 服务端响应、429 限流响应不重试2xx、3xx 及其余 4xx鉴权/请求错误重试无意义默认值3 次尝试初始 2 次重试、初始延迟 500ms、退避倍率 2延迟序列 500ms → 1000ms可用{ attempts, delayMs, backoff, fetch }定制。示例import { connect } from tursodatabase/sync; import { retryFetch } from tursodatabase/sync-common; const db await connect({ path: local.db, url: libsql://..., fetch: retryFetch(), // 默认参数 // fetch: retryFetch({ attempts: 5, delayMs: 1000 }), });运行与测试同步包在仓库内的测试方式见 native package.json 的 scripts可以复现常规测试npm test需要先构建本地同步服务器二进制LOCAL_SYNC_SERVER../../../../../target/debug/tursodb并用 vitest 运行排除 remote-write 测试远程写测试npm run test:remote-write测试用例可参考 promise.test.ts 与 remote-write.test.ts浏览器/WASM 场景对应 wasm 包tursodatabase/database-wasm生态其入口文件支持 Vite/Turbopack 的构建适配见index-vite-dev-hack.ts、index-turbopack-hack.ts等。与周边包的搭配纯本地内存数据库无网络tursodatabase/database示例见 native README支持内存库、文件库与transactionAsync事务浏览器环境tursodatabase/database-wasmAPI 与 Node 版本一致无状态 serverless 场景tursodatabase/serverless需要本地↔云端双向同步tursodatabase/sync即本文主题。仓库中的可运行示例还可在 examples/javascript 下找到如database-node、sync-node、sync-wasm-vite、concurrent-writes、encryption等其中sync-node与sync-wasm-vite是与本文主题直接对应的端到端参考实现建议结合阅读。小结tursodatabase/sync提供了一条在 Node.js/浏览器中把本地 Turso 数据库与 Turso Cloud 保持双向同步的路径通过connect一次配置path、url、authToken即可获得与tursodatabase/database完全一致的数据库 API并叠加pull/push/sync三个同步方法。在此基础上其配置体系还覆盖了长轮询监听、动态鉴权、延迟同步、云端加密、冲突改写transform、远程写、部分同步等进阶能力底层则由 Rust 同步引擎以生成器协议驱动 HTTP/本地 I/O 请求循环配合多把异步锁保证同步与本地执行的安全交错。使用时请留意remoteWritesExperimental与partialSyncExperimental等仍处于实验阶段的特性并始终为生产数据保留备份。【免费下载链接】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),仅供参考
返回列表