关于 sqlite-to-fast-sql
sqlite-to-fast-sql 是将 Capacitor 应用从桥接式 SQLite 插件迁移到 @capgo/capacitor-fast-sql 的技能,适用于需要保留本地数据的开发者。内容涵盖 API 替换、平台配置、加密选项及数据迁移方案。
主要功能
- 01盘点现有 SQL 插件与数据结构
- 02映射查询、写入和事务 API
- 03配置 iOS、Android 与 Web
- 04迁移旧数据库并验证数据
- 05配置可选 SQLCipher 加密
适用场景
- 01将 SQLite 插件替换为 Fast SQL
- 02迁移期间保留已有本地数据库
- 03排查大查询或批量写入性能问题
- 04为数据库启用加密并测试迁移
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ cap-go/ capgo-skills --skill sqlite-to-fast-sql安装后在 Claude Code 中输入/sqlite-to-fast-sql确认已加载。
附带文件metadata.json
详细介绍
SQLite 到 Fast SQL 迁移
将基于桥接的 SQL 插件替换为 @capgo/capacitor-fast-sql,同时保留用户数据。
适用场景
满足以下情况时触发:
package.json中包含@capacitor-community/sqlite、cordova-sqlite-storage、@capawesome-team/capacitor-sqlite、ORM capacitor 驱动或其他 SQLite 插件,且用户希望使用 Fast SQL。- 大型
SELECT查询或同步写入速度缓慢,因为每一行都要以 JSON 格式通过 Capacitor 桥接传输。 - 应用需要加密、事务、批量写入、BLOB 或加密键值存储。
以下情况不适用:
- 仅使用
@capacitor/preferences或 IndexedDB 的应用 ->capacitor-offline-first。 - 使用
@ionic-enterprise/secure-storage/ Identity Vault 的应用 ->ionic-enterprise-sdk-migration。 - 已使用 Fast SQL、需要设计架构或同步逻辑的应用 ->
capacitor-offline-first。
当前项目快照
检测到与 SQL 相关的软件包:
!node -e "const fs=require('fs');if(!fs.existsSync('package.json'))process.exit(0);const pkg=JSON.parse(fs.readFileSync('package.json','utf8'));const needles=['sqlite','sqlcipher','typeorm','watermelondb','pouchdb','@capacitor-community/sqlite','@capawesome-team/capacitor-sqlite','@capgo/capacitor-fast-sql'];const out=[];for(const section of ['dependencies','devDependencies']){for(const [name,version] of Object.entries(pkg[section]||{})){if(needles.some((needle)=>name.includes(needle)))out.push(section+'.'+name+'='+version)}}console.log(out.sort().join('\n'))"
Fast SQL 的区别
- 原生 SQLite 通过
localhost上受令牌保护的 HTTP 服务访问,而非通过 Capacitor 桥接,因此大型结果集和批次可以避免桥接序列化。这就是为什么必须配置 iOS ATS 和 Android 明文传输。 - 插件主版本与 Capacitor 主版本一致(Capacitor 8 对应 v8)。当前版本:8.2.x。
- 数据库文件:iOS 为
Documents/<database>.db,Android 为<filesDir>/<database>.db。其他插件使用不同的路径和名称,因此不会自动读取现有数据。 - Web:使用官方
@sqlite.org/sqlite-wasm和 OPFS 持久化(依赖已打包,无需安装sql.js)。旧版本使用 sql.js + IndexedDB;这些数据不会自动迁移。 - 加密:SQLCipher,按平台选择启用。
流程
第 1 步:盘点
阅读 package.json 并搜索数据层。记录:插件及版本、数据库名称、架构/迁移机制(user_version、升级语句、ORM 迁移)、事务使用情况、BLOB、加密(以及密钥来源)、JSON 导入/导出、Web 支持情况和大致数据量。更改代码前先报告这些信息。
第 2 步:映射 API
import { FastSQL, KeyValueStore } from '@capgo/capacitor-fast-sql';
const db = await FastSQL.connect({ database: 'app' }); // { encrypted, encryptionKey, readOnly }
const rows = await db.query('SELECT * FROM todo WHERE done = ?', [0]);
const { rowsAffected, insertId } = await db.run('INSERT INTO todo (title) VALUES (?)', ['A']);
await db.execute('CREATE TABLE IF NOT EXISTS todo (id INTEGER PRIMARY KEY, title TEXT, done INTEGER DEFAULT 0)');
await db.executeBatch([{ statement: 'INSERT INTO log (m) VALUES (?)', params: ['x'] }]);
await db.transaction(async (tx) => { await tx.run('UPDATE a SET n = n - 1'); await tx.run('UPDATE b SET n = n + 1'); });
await FastSQL.disconnect('app');
@capacitor-community/sqlite | Fast SQL |
|---|---|
new SQLiteConnection(CapacitorSQLite)、createConnection(name, encrypted, mode, version, readonly)、db.open() | FastSQL.connect({ database, encrypted, encryptionKey, readOnly }) |
db.query(sql, values) -> { values } | db.query(sql, params) -> rows array |
db.run(sql, values) -> { changes: { changes, lastId } } | db.run(sql, params) -> { rowsAffected, insertId } |
db.execute(multiStatementSql) | 每条语句调用一次 db.execute(sql),或使用 executeBatch |
db.executeSet([{ statement, values }]) | db.executeBatch([{ statement, params }]) |
beginTransaction/commitTransaction/rollbackTransaction、调用中的 transaction 标志 | db.transaction(cb) 或 beginTransaction() / commit() / rollback() |
addUpgradeStatement + 版本号 | 使用自己的 PRAGMA user_version 迁移运行器 |
closeConnection(name) | FastSQL.disconnect(name) |
importFromJson / exportToJson | 不提供;使用 executeBatch 写入行 |
cordova-sqlite-storage db.executeSql(sql, params, ok, err) / db.transaction(tx => tx.executeSql(...)) | db.query/db.run 和 db.transaction(async tx => ...) |
键值数据(Ionic Storage、类似 Preferences 的封装)-> 使用 KeyValueStore.open({ database, encrypted, encryptionKey, store }),并配合 set/get/has/remove/clear/keys 使用。
步骤 3:安装和配置
npm install @capgo/capacitor-fast-sql
npx cap sync
iOS ios/App/App/Info.plist(仅限回环地址;不会削弱其他主机的 ATS):
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
Android android/app/src/main/res/xml/network_security_config.xml,并在 <application> 上通过 android:networkSecurityConfig="@xml/network_security_config" 引用:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">localhost</domain>
<domain includeSubdomains="false">127.0.0.1</domain>
</domain-config>
</network-security-config>
如果应用已有网络安全配置,请合并 domain-config,而不是替换整个文件。
加密(仅当 encrypted: true 时):
- Android:在
android/app/build.gradle的 dependencies 中添加implementation 'net.zetetic:sqlcipher-android:4.13.0'(或当前版本)。 - iOS(CocoaPods):在
ios/App/Podfile中添加pod 'CapgoCapacitorFastSql/SQLCipher', :path => '../../node_modules/@capgo/capacitor-fast-sql',然后运行pod install。对于 SPM 项目,请查看插件 README,了解当前的 SQLCipher 选项。 - 不要将密钥放在 JS 源代码中:使用
@capgo/capacitor-native-biometric存储密钥,或从后端获取密钥。
Web(仅当应用面向 Web 发布时):提供 Cross-Origin-Opener-Policy: same-origin 和 Cross-Origin-Embedder-Policy: require-corp,并在 Vite 中添加 optimizeDeps.exclude: ['@sqlite.org/sqlite-wasm']。在首次 connect() 之前调用 CapgoCapacitorFastSql.configureWeb({ ... }) 是可选的,在原生平台上则不会执行任何操作。
步骤 4:保留现有数据
与用户一起选择一种方案:
- 双插件发布(最安全):保留旧插件一个发布周期。首次启动时,如果缺少
migrated标记,则从旧插件读取表,在事务中通过executeBatch将其写入 Fast SQL,验证计数,然后设置该标记。下一次发布时移除旧插件。 - 复制文件:在首次
connect()之前,将旧.db文件复制到 Fast SQL 的路径(旧版社区插件的文件通常命名为<name>SQLite.db;请先在设备上确认实际路径)。加密文件只有在使用相同密钥和兼容的 SQLCipher 版本时才能继续使用。 - 从服务器重新同步:当本地数据只是缓存时可以接受;请与用户确认。
步骤 5:替换代码并移除旧插件
在现有数据访问层中替换导入和调用;保留架构和迁移步骤。然后(如果选择方案 1,则在过渡发布之后):
npm uninstall @capacitor-community/sqlite # or the plugin in use
npx cap sync
验证
- 清理后,
rg -n "@capacitor-community/sqlite|cordova-sqlite|CapacitorSQLite|SQLiteConnection" -g '!node_modules' src不应返回任何内容。 - 升级测试:安装当前商店版本,创建数据,再覆盖安装新版本;行数应一致。
- 在两个平台上进行冒烟测试:创建、读取、更新、删除、事务回滚(在
transaction中抛出异常并确认没有部分写入)、BLOB 往返(Uint8Array)。 - 加密数据库:使用错误密钥无法打开;使用普通
sqlite3无法读取该文件。 - 前后测量大型查询,确认达到性能目标。
错误处理
| 错误 / 症状 | 修复方法 |
|---|---|
iOS:对 http://localhost:<port> 的请求失败,提示 The resource could not be loaded because the App Transport Security policy requires the use of a secure connection | 添加 NSAllowsLocalNetworking |
Android:出现 net::ERR_CLEARTEXT_NOT_PERMITTED 或 CLEARTEXT communication to localhost not permitted by network security policy | 添加 localhost 的 network_security_config.xml,并在清单中引用它 |
iOS:出现 Encryption is not available in this build. Add SQLCipher to enable encryption. | 安装 SQLCipher 子规范,或使用 encrypted: false |
Android:出现 Encryption is not available. ... to your app's build.gradle to enable encryption. | 在应用模块中添加 net.zetetic:sqlcipher-android |
Encryption key is required when encrypted is true | 在设置 encrypted: true 时传入 encryptionKey |
| 更新后应用启动时数据库为空 | 文件路径已更改;执行步骤 4 的数据迁移 |
Web:出现 OPFS / SharedArrayBuffer 错误 | 缺少 COOP/COEP 标头,或 Vite 预打包了 sqlite-wasm |
query 返回对象,但代码预期的是 { values } | 这是旧社区插件的结果格式;更新调用方以使用行数组 |