跳转至正文

2026 年 @capacitor-community/sqlite 的替代方案

正在寻找 @capacitor-community/sqlite 的替代方案?将其与 Capgo 高速 SQL 进行对比,并逐步迁移您的 Capacitor SQLite code 及用户数据。

2026 年 @capacitor-community/sqlite 的替代方案

主要的替代方案是 @capacitor-community/sqlite 在 Capacitor 8 上是 @capgo/capacitor-fast-sql:一款适用于 iOS、Android 和 Web 的原生 SQLite 插件,它将 SQLCipher 设为可选,并通过本地 HTTP 通道而非 Capacitor bridge 发送查询数据。本指南将对两者进行客观对比,告诉你何时应继续使用社区插件,并指导你如何迁移 code 以及用户现有的数据库。

为什么团队会寻找替代方案

@capacitor-community/sqlite 多年来一直是 Capacitor 默认的 SQLite 插件,且目前仍在维护(2026 年 8 月发布了 8.1.1 版本)。人们选择迁移的原因非常明确:

  1. Bridge 序列化问题。 每个查询结果都必须通过 Capacitor bridge 以 JSON 格式传输。对于小规模查询这没问题,但在进行同步或搜索并加载数千行数据时,性能损耗会非常明显。
  2. SQLCipher 始终被包含在内。 即使你从不使用加密,该插件在 iOS 和 Android 上也依赖 SQLCipher。这增加了原生包体积,并意味着你的二进制文件中包含加密 code,在填写出口合规性问卷时必须考虑这一点。
  3. Web 存储模型。 在 Web 端,它使用 jeep-sqlite 组件:sql.js 运行在内存中,并在你调用 saveToStore()时持久化到 IndexedDB。你必须记得手动保存,且整个数据库都存在于内存中。
  4. 庞大的 API 攻击面。 包含连接封装、一致性检查、只读与非规范连接、同步表、JSON 导入导出。功能强大,但对于只想“运行 SQL”的用户来说学习成本较高。
  5. 每个 App 使用一个密码。 加密使用由插件存储的单一密钥 (setEncryptionSecret),该密钥由 App 中所有加密数据库共享。

对比分析

@capacitor-community/sqlite 8.1 @capgo/capacitor-fast-sql 8.2
支持平台 iOS, Android, Web, Electron iOS, Android, Web
数据路径 Capacitor bridge 带有单连接 Token 的本地 HTTP 服务器 (Native)
Web 引擎 jeep-sqlite (sql.js + IndexedDB,手动) saveToStore) 官方 @sqlite.org/sqlite-wasm 支持 OPFS,写入直接存入文件
加密 始终内置 SQLCipher,由单个插件管理的密码 可选 SQLCipher,按数据库传入密钥 connect()
Swift Package Manager 是 (Package.swift) 是 (Package.swift)
Schema 版本控制 upgradeStatements / addUpgradeStatement 通常由您自定义 PRAGMA user_version
JSON 导入/导出,同步表 是 否
从 assets 预加载数据库 copyFromAssets() 提前手动复制文件 connect()
键值对辅助工具 否 KeyValueStore
BLOB 数据 是 是的,作为 Uint8Array
ORM 支持 内置 TypeORM capacitor 驱动 自定义驱动(Kysely 兼容性良好)
额外的原生配置 Web 端:复制 sql-wasm.wasm iOS NSAllowsLocalNetworking,Android localhost 明文传输规则
维护者 Capacitor 社区 Capgo

何时继续使用社区插件

务实一点。如果满足以下条件,请继续使用:

  • 你正在发布一个 Electron 构建,
  • 你正在使用 TypeORM (其 capacitor 驱动是基于社区插件编写的,参见 配合 Capacitor 使用 TypeORM),
  • 你依赖于 JSON 导入/导出或同步表 且不想重新构建它们,
  • 你的查询量很小,且目前应用运行良好。

何时 Fast SQL 更合适

如果符合以下情况,请迁移:

  • 你需要加载或写入大数据集(同步引擎、离线目录、搜索索引、CRDT 日志),
  • 你只想对部分数据库进行加密,并使用 Keychain 或 Keystore 中的密钥,
  • 你不想在不需要加密的应用中引入 SQLCipher,
  • 你希望通过 OPFS 在 Web 端使用真实的 SQLite 文件,而非内存副本,
  • 你想要一个简单的 API:连接、查询、执行、事务。

有关 Fast SQL 的完整指南,请参阅 如何在 Capacitor 应用中使用 SQLite.

第 1 步:在旧插件旁安装 Fast SQL

请保留社区版插件一个版本周期,以便迁移现有数据。

bun add @capgo/capacitor-fast-sql
bunx cap sync

Fast SQL 所需的 Native 配置:

  • iOS: NSAppTransportSecurity > NSAllowsLocalNetworking = true 在 Info.plist.
  • Android: 将 network_security_config.xml 允许明文传输 localhost 和 127.0.0.1,引用自清单文件。
  • 加密: net.zetetic:sqlcipher-android 在 Android 应用模块和 CapgoCapacitorFastSql/SQLCipher iOS pod 中。详情请参阅 在 Capacitor 中加密 SQLite.
  • Web: Cross-Origin-Opener-Policy: same-origin 和 Cross-Origin-Embedder-Policy: require-corp 用于 OPFS 的请求头。

步骤 2:映射 API

打开数据库

改造前:

import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite';

const sqlite = new SQLiteConnection(CapacitorSQLite);
const db = await sqlite.createConnection('app', false, 'no-encryption', 1, false);
await db.open();

改造后:

import { FastSQL } from '@capgo/capacitor-fast-sql';

const db = await FastSQL.connect({ database: 'app', walMode: true, performancePresets: true });

FastSQL.connect() 如果数据库已打开,则返回现有连接,因此无需 isConnection / retrieveConnection 繁琐操作。

方法映射

社区插件 快速 SQL
createConnection() + open() FastSQL.connect({ database })
closeConnection(name) FastSQL.disconnect(name)
db.query(sql, values) 返回 { values } db.query(sql, params) 返回行
db.run(sql, values) 返回 { changes: { changes, lastId } } db.run(sql, params) 返回 { rowsAffected, insertId }
db.execute(multiStatementString) 一个 db.execute(sql) 每个语句,或 db.executeBatch([...])
db.executeSet(set) db.executeBatch(ops) 带 { statement, params }
beginTransaction / commitTransaction / rollbackTransaction db.transaction(async (tx) => ...) 或 beginTransaction() / commit() / rollback()
addUpgradeStatement / upgradeStatements 一个 PRAGMA user_version 迁移运行器
copyFromAssets() 复制已打包的 .db 移至 Directory.Data 在第一个之前 connect()
setEncryptionSecret() + mode: 'secret' encrypted: true, encryptionKey 在 connect()
initWebStore() / saveToStore() 不需要,OPFS 会持久化写入

查询与写入

改造前:

const res = await db.query('SELECT * FROM notes WHERE pinned = ?', [1]);
const notes = res.values ?? [];

const { changes } = await db.run('INSERT INTO notes (title) VALUES (?)', ['Hello']);
const id = changes?.lastId;

改造后:

const notes = await db.query('SELECT * FROM notes WHERE pinned = ?', [1]);

const { insertId } = await db.run('INSERT INTO notes (title) VALUES (?)', ['Hello']);

这两个插件都以列名为键,将行返回为对象。

多语句执行

社区版插件 execute() 接受以以下符号分隔的包含多个语句的字符串: ;。Fast SQL 在每次调用时仅准备一条语句。请拆分您的 SQL,或者更好的做法是将语句存为数组:

const schema = [
  'CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL)',
  'CREATE INDEX IF NOT EXISTS idx_notes_title ON notes (title)',
];

await db.executeBatch(schema.map((statement) => ({ statement })));

不要仅通过 ; 使用简单的 split(';') 进行拆分,因为如果语句中包含 trigger 体或带有分号的字符串字面量,会导致错误。

将语句升级至 user_version

该社区插件也将 schema 版本存储在 PRAGMA user_version 中。如果保持版本号一致,在完成步骤 3 的文件迁移后,现有用户的数据库将直接处于正确的版本。

import type { SQLConnection } from '@capgo/capacitor-fast-sql';

// Same content as your old upgrade statements, index 0 = version 1
const versions: string[][] = [
  ['CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL)'],
  ['ALTER TABLE notes ADD COLUMN pinned INTEGER NOT NULL DEFAULT 0'],
];

export async function migrate(db: SQLConnection) {
  const [{ user_version }] = await db.query('PRAGMA user_version');
  for (let v = Number(user_version); v < versions.length; v++) {
    await db.transaction(async (tx) => {
      for (const statement of versions[v]) await tx.execute(statement);
      await tx.execute(`PRAGMA user_version = ${v + 1}`);
    });
  }
}

在依赖此方案前,请先在现有安装版本上检查实际的 user_version 。如果不确定,可以在当前版本的旧插件中将其记录到 logs 中。

预置数据库

该社区插件的 copyFromAssets() 会在首次启动时复制 bundled 数据库。使用 Fast SQL 时,请在连接前将文件放入插件指定的路径。Fast SQL 将数据存储在 <name>.db 在 Documents iOS 的 files 以及 Android 的 app Directory.Data 在 @capacitor/filesystem:

import { Directory, Filesystem } from '@capacitor/filesystem';
import { FastSQL } from '@capgo/capacitor-fast-sql';

async function openCatalog() {
  const exists = await Filesystem.stat({ path: 'catalog.db', directory: Directory.Data })
    .then(() => true)
    .catch(() => false);

  if (!exists) {
    const blob = await (await fetch('/assets/catalog.db')).blob();
    const base64 = await new Promise<string>((resolve) => {
      const reader = new FileReader();
      reader.onloadend = () => resolve((reader.result as string).split(',')[1]);
      reader.readAsDataURL(blob);
    });
    await Filesystem.writeFile({ path: 'catalog.db', data: base64, directory: Directory.Data });
  }
  return FastSQL.connect({ database: 'catalog', readOnly: true });
}

目录中,两者均为。对于大文件,请分块 download,或者通过传输压缩文件并使用 file plugin 的 native copy 功能,避免在 JavaScript 中使用 base64。

步骤 3:迁移现有用户数据

更新应用的用户的数据库是由社区插件创建的。它位于不同的路径,且名称也不同:

社区插件 快速 SQL
iOS Documents/<name>SQLite.db (默认 iosDatabaseLocation) Documents/<name>.db
Android databases/<name>SQLite.db files/<name>.db

方案 A:复制文件(非加密数据库)

最快且能保留所有内容:索引、触发器、 user_version.

import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite';
import { Directory, Filesystem } from '@capacitor/filesystem';
import { Preferences } from '@capacitor/preferences';

export async function moveCommunityDatabase(name: string): Promise<void> {
  const done = await Preferences.get({ key: `sqlite-moved:${name}` });
  if (done.value === '1') return;

  const sqlite = new SQLiteConnection(CapacitorSQLite);
  const exists = (await sqlite.isDatabase(name)).result;
  if (exists) {
    const conn = await sqlite.createConnection(name, false, 'no-encryption', 1, false);
    await conn.open();
    await conn.execute('PRAGMA wal_checkpoint(TRUNCATE)', false).catch(() => undefined);
    const { url } = await conn.getUrl();
    await sqlite.closeConnection(name, false);

    if (url) {
      await Filesystem.copy({ from: url, to: `${name}.db`, toDirectory: Directory.Data });
    }
  }
  await Preferences.set({ key: `sqlite-moved:${name}`, value: '1' });
}

在首次调用前执行 FastSQL.connect({ database: name }). 注意:

  • getUrl() (iOS 和 Android) 返回数据库文件 URL。传入完整的 file:// 不带 URL 的 directory 可以让 Filesystem 插件读取沙盒内的任何路径。
  • 先关闭连接并进行 checkpoint,可以确保没有最近的写入操作留在 -wal 文件中。
  • 保留旧文件一个版本,待确认无误后,再使用社区版连接的 delete() 方法将其删除。随后移除该社区插件。

方案 B:在 JavaScript 中复制行(加密数据库或 Schema 变更)

当源文件使用社区插件存储的密钥加密时,最简单且安全的方法是让该插件解密,并将行复制到新的 Fast SQL 数据库中。这样你还可以使用来自安全存储的新数据库密钥进行加密。

import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite';
import { FastSQL } from '@capgo/capacitor-fast-sql';
import { Preferences } from '@capacitor/preferences';

export async function copyRows(name: string, target: { encryptionKey?: string }) {
  // Record which destination mode was migrated, so a later call with a different target fails loudly
  const mode = target.encryptionKey ? 'encrypted' : 'plain';
  const done = await Preferences.get({ key: `sqlite-copied:${name}` });
  if (done.value === mode) return;
  if (done.value) throw new Error(`${name} was already copied as ${done.value}, not ${mode}`);

  const sqlite = new SQLiteConnection(CapacitorSQLite);
  const src = await sqlite.createConnection(name, true, 'secret', 1, false);
  await src.open();

  try {
    const dst = await FastSQL.connect({
      database: name,
      encrypted: Boolean(target.encryptionKey),
      encryptionKey: target.encryptionKey,
    });

    const objects = ((await src.query(
      `SELECT type, name, sql FROM sqlite_master
       WHERE sql IS NOT NULL AND name NOT LIKE 'sqlite_%'`,
    )).values ?? []) as { type: string; name: string; sql: string }[];
    const tables = objects.filter((o) => o.type === 'table');
    const others = objects.filter((o) => o.type !== 'table');
    const version = (await src.query('PRAGMA user_version')).values?.[0]?.user_version ?? 0;

    await dst.transaction(async (tx) => {
      for (const t of tables) await tx.execute(t.sql);
      for (const t of tables) {
        const rows = (await src.query(`SELECT * FROM "${t.name}"`)).values ?? [];
        if (!rows.length) continue;
        const cols = Object.keys(rows[0]);
        const statement = `INSERT INTO "${t.name}" (${cols.map((c) => `"${c}"`).join(', ')}) VALUES (${cols.map(() => '?').join(', ')})`;
        await tx.executeBatch(rows.map((r) => ({ statement, params: cols.map((c) => r[c]) })));
      }
      for (const o of others) await tx.execute(o.sql);
      await tx.execute(`PRAGMA user_version = ${Number(version)}`);
    });

    // Only mark the copy as done once the transaction has committed
    await Preferences.set({ key: `sqlite-copied:${name}`, value: mode });
  } finally {
    await sqlite.closeConnection(name, false);
  }
}

使用 'no-encryption' 和 false 在 createConnection 如果源文件未加密。社区插件需要 iosIsEncryption / androidIsEncryption 在 capacitor.config 利用其加密模式(如果你之前已使用过)。对于大表,请使用分页功能进行 WHERE rowid > ? ORDER BY rowid LIMIT 5000.

两个插件都使用 SQLCipher 4 的默认设置,因此使用相同的密码也可以直接用 Fast SQL 打开加密文件。不过,社区插件会在内部管理该密码,而行复制操作则避免了对这一细节的依赖。

第 4 步:移除旧插件

在完成一两次迁移发布后:

bun remove @capacitor-community/sqlite jeep-sqlite
bunx cap sync

移除 sql-wasm.wasm 从你的 assets 以及任何 jeep-sqlite 配置于 main.ts。移除插件也会移除其 SQLCipher 依赖,因此如果你没有选择 Fast SQL 的加密功能,iOS 和 Android 的二进制文件体积会更小。

数据迁移 code 是 JavaScript 编写的,因此可以随 Capgo Live Update一起发布,但添加 Fast SQL 的版本属于原生变更,需要进行 store build。请先发布 Native Build。 Capgo 构建 如果你手边没有 Mac,也可以在云端进行构建(自 2026 年 4 月起,App Store 上传需要 Xcode 26 或更高版本)。

故障排除

Fast SQL 连接很快,但在 iOS 上所有查询都会失败。 NSAllowsLocalNetworking 应用中缺少 Info.plist,或者在添加后未重新构建应用。

Android: CLEARTEXT communication to localhost not permitted. 将 localhost 添加到 domain-config 你的网络安全配置中。如果你已经有了 SSL pinning 配置,请将它们合并。

只有部分 schema 被创建了。 You passed a multi-statement string to execute()。请将其拆分为数组。

INSERT ... RETURNING 在 Android 上不返回任何内容。 在 Fast SQL 8.2 中,Android 仅对以以下内容开头的语句返回行: SELECT, PRAGMA 或 EXPLAIN。请使用 insertId from run().

Android 读取时的 Boolean 类型不匹配。 传递 1/0 而不是 true/false 在查询参数中。Android 将读取查询参数绑定为 text 类型。

复制的数据库为空。 该社区插件配置了自定义的 iosDatabaseLocation,或者源名称不一致。记录由以下内容返回的 URL: getUrl().

旧插件中的 Web 数据已丢失。 社区插件通过 IndexedDB 存储 Web 数据, jeep-sqlite而 Fast SQL 使用 OPFS。请从后端重新同步 Web 客户端,或使用旧插件 exportToJson 导出并将其行数据导入 Fast SQL。

其他方案

  • @capgo/capacitor-data-storage-sqlite 如果你真正需要的是基于 SQLite 的字符串键值存储。请参阅 Capacitor 中的键值存储.
  • 在其之上构建的 ORM 或查询构建器: Kysely 可以通过一个简短的自定义驱动程序与 Fast SQL 配合使用。 Drizzle 目前更适合社区插件。

完整的 Fast SQL API 请参阅 插件文档 以及 插件页面.

为 Capacitor 应用提供实时更新

当 Web 层 Bug 已上线时,通过 Capgo 推送修复,不必等 App Store 审核数天。用户会在后台获取更新,而原生变更仍走常规审核流程。

博客最新文章

Capgo 为你提供打造真正专业移动应用所需的深度洞察。