- Web Storage上で直接SQLを実行するライブラリは原則存在しません。localStorage/sessionStorageは単純な同期的キー・バリュー層であり、SQL処理に必要なトランザクションやインデックス、非同期処理などを持たないためです。過去にWebSQL(SQLiteベース)が提案されましたが、現在は非推奨・削除されています。唯一に近いものは、SQLiteをWASM化してlocalStorageをVFSとして使う仕組み(SQLite公式WASMの「kvvfs」)など特殊な実装例です。
- 代替として、IndexedDBベースのSQL実行やメモリDB+永続化が使われます。代表例はsql.js(SQLiteのWASM版、メモリDBでインポート/エクスポートで永続化)、absurd-sql(sql.js+IndexedDBバックエンド。SQLiteファイルをIndexedDBにチャンク保存)、PGlite(WASM版Postgres、インメモリ&IndexedDB永続化対応)などです。これらはSQL互換性が高く、トランザクションや性能もSQLiteレベルですが、IndexedDBやOPFSなどを用いるためブラウザサポートやサイズ制限に注意が必要です。
- WebSQL(旧仕様)は現在サポート外です。Chromium系では2022年に非推奨、2024年に完全削除されました。WebSQLの代替として、WASM版SQLite(OPFSバックエンド)やIndexedDBベースのSQLライブラリが公式に推奨されています。
- 技術的理由(localStorageがSQLに不向きな理由): localStorageは「同期的」「単一キー・バリュー」「5~10MB程度のサイズ制限」「トランザクションや原子性がない」「Worker未対応」など、多くのSQL必須機能が欠けます。例えば複数行挿入の原子性を保証できず、複雑な問い合わせができず、データ型も文字列のみなどです。
- 関連議論: StackOverflowやGitHubでも「localStorageでSQLiteをエミュレートできるか」という質問が複数あります。StackOverflowではsql.jsやalasql、SequelSphere等が提案例として挙がっています。TypeORMのIssueでは、sql.jsのローカル保存が同期処理でパフォーマンス問題を起こす例も報告されています。
- 比較表: 以下に主要なアプローチの比較を示します。
(3) localStorageの技術的制約
- 同期的API: localStorage/sessionStorageはいずれも同期処理であり、操作するとJavaScript実行がブロックされます。大きなデータ操作ではUIのフリーズを招きます。
- トランザクション・原子性なし: 内部は単一キー毎の書き込みで、複数操作を原子化できません。ロールバック機能や排他制御がなく、複雑な更新時に整合性が保てません。
- 単純なKey/Valueモデル: キーは文字列、値も文字列でしか保持できません。SQLite等が用意するBLOBや数値型等がなく、複雑なオブジェクトはJSON化が必要です。
- 容量制限: 多くのブラウザで約5MB程度に制限されています(2バイト文字コーディングのため実質4MB以下)。これを超えると書き込み失敗します。
- ワーカ利用不可: localStorageはメインスレッド専用で、Web Workerからアクセスできません。バックグラウンド処理に不向きです。
- クロスタブ/セキュリティ: 同一オリジン内で共有されますが、同時書き込み時の制御がなく、片方のタブで更新しても他タブに自動通知されるのみです(競合防止機構なし)。またXSSに弱く、セキュアなデータ格納には不適切です。
(4) 参考議論例
- StackOverflow: 「localStorageでSQLiteをエミュレートするライブラリ」は何か?という質問では、sql.jsやalasql、SequelSphereなどが回答として挙がりました。alasqlは自身でSQLエンジンを持ち、手動でlocalStorageにエクスポート/インポートする例が示されています。また、TypeORMのIssueでは、sql.jsドライバがlocalStorage同期保存のため起動が数秒停止すると報告され、IndexedDB(localForage)に差し替える話が出ました。
- GitHub Issues: 「Web SQLは非推奨にすべきか」というディスカッションや、「sql.jsドライバのIndexedDB対応」など、多数の議論があります。例えばElectron-SQLiteプロジェクトではWebSQL削除を検討中です。
(6) コード例
sql.js+IndexedDB永続化(簡易例)
この例では、sql.jsでDBを操作し、
db.export()で得たバイト列をIndexedDBに保存しています。IndexedDBにより非同期で永続化できますが、読み込みや再インポートも自前実装が必要です。absurd-sql基本セットアップ
absurd-sqlでは、IndexedDBBackendを使いSQLiteFSを構築して**/sql/db.sqlite**のようにマウントします。この例ではデータがIndexedDB上にチャンク単位で保存され、
db操作後は永続化されます。注意点として、SharedArrayBufferの有無でSafari等対応差異があります。localStorageにトランザクションがない例
このようにlocalStorageにはトランザクション管理機能がないため、途中で失敗すると部分的にしかデータが書き込まれず、データ不整合の恐れがあります。
参考資料
主要情報は以下を参照しました。
- SQLite公式ドキュメント – WebAssembly版SQLiteにおけるlocalStorage/sessionStorage対応(kvvfs)
- absurd-sql GitHubリポジトリREADME
- PGlite GitHubリポジトリREADME
- sql.js GitHubリポジトリREADME
- MDN Web Storage API解説
- Chrome Developersブログ “Web SQLの非推奨化”
- StackOverflow Q&A「localStorageでSQLiteをエミュレートするライブラリは?」
- TypeORM GitHub Issue (#3554) – sql.jsのローカル保存が同期的で遅い問題
参考リンク(上位8件): SQLite公式Persistent Storage(WASM)、Chrome Developersブログ、sql.js公式README、absurd-sql README、PGlite README、MDN Web Storage API、StackOverflow例、localStorageDB README。