
SQL.js 是纯前端 SQLite 实现,所有数据库操作均在内存中进行,无法直接写回本地 .db 文件;HTTP 协议禁止浏览器向任意 URL 发起写入请求,因此必须通过服务端中转或采用客户端持久化方案(如 IndexedDB)来实现数据持久化。
sql.js 是纯前端 sqlite 实现,所有数据库操作均在内存中进行,无法直接写回本地 `.db` 文件;http 协议禁止浏览器向任意 url 发起写入请求,因此必须通过服务端中转或采用客户端持久化方案(如 indexeddb)来实现数据持久化。
SQL.js 是一个将 SQLite 编译为 WebAssembly 的纯前端库,它在浏览器内存中加载并运行 SQLite 引擎,不依赖服务端、不访问文件系统、也不具备写入原始 .db 文件的能力。你当前的代码:
const db = new SQL.Database(new Uint8Array(buf));
db.run("CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, quantity INTEGER)");
db.exec("INSERT INTO items (id, quantity) VALUES (32, 34)");
——这段逻辑完全正确,但它仅在 db 实例的内存中创建表并插入数据。一旦页面刷新或关闭,该 db 对象即被销毁,所有变更彻底丢失。更关键的是:浏览器出于安全沙箱限制,根本无法将修改后的数据库字节写回服务器上的 src/db/sql2.db 文件。这是 HTTP 协议与同源策略的根本约束(例如,若前端可任意 PUT/POST 覆盖任意 URL 资源,整个 Web 将面临严重安全风险)。
✅ 正确的数据持久化路径
| 方案 | 适用场景 | 实现要点 |
|---|---|---|
| 服务端持久化(推荐) | 需要多用户共享、强一致性、备份能力 | 使用 Node.js + SQLite/PostgreSQL,前端通过 fetch 提交 CRUD 请求(如 POST /api/items),服务端处理并落盘 |
| 客户端持久化(离线优先) | 单用户、离线可用、无需后端 | 将 db.export() 得到的 Uint8Array 存入 localStorage(限小数据)或 IndexedDB(推荐),页面加载时用导出数据重建 SQL.Database |
| 文件下载导出(辅助) | 用户主动保存快照 | 调用 db.export() 后生成 Blob 并触发下载: js const data = db.export(); const blob = new Blob([data], { type: 'application/octet-stream' }); const url = URL.createObjectURL(blob); const a = Object.assign(document.createElement('a'), { href: url, download: 'mydb.db' }); document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); |
⚠️ 注意事项
- ❌ 不要尝试用 fetch(..., { method: 'PUT' }) 直接覆盖 .db 文件——现代浏览器会拒绝跨域写入,即使同域也需服务端显式支持(且极不安全);
- ❌ 避免将大量数据存入 localStorage(通常上限 5–10 MB,且阻塞主线程);
- ✅ 在初始化时始终检查是否已有持久化数据:先从 IndexedDB 加载,无则用初始 .db 文件创建新库;
- ✅ 对频繁读写的场景,建议封装 DatabaseManager 类,统一处理加载、导出、自动同步等逻辑。
总之,SQL.js 本身没有缺陷,而是其设计定位明确:提供 SQLite 语法兼容的客户端计算能力,而非文件系统代理。选择合适的数据持久层(服务端 or IndexedDB),再让 SQL.js 承担查询与事务逻辑,才是构建可靠本地数据库应用的专业实践。











