コンテンツへスキップ

Getting Started with Fast SQL

このガイドでは、高性能なSQLiteデータベースアクセスのための**@capgo/capacitor-fast-sql**プラグインをインストールして設定する方法を説明します。

Capacitor用の従来のSQLiteプラグインは、標準的なJavaScriptブリッジに依存してWebコードとネイティブコード間の通信を行っています。小規模な操作では問題ありませんが、大量のデータを転送する必要がある場合、ブリッジが大きなボトルネックになります。すべてのデータはJSONにシリアル化され、ブリッジ経由で送信され、その後、相手側でデシリアル化されます。このシリアル化のオーバーヘッドにより、数千行のデータまたは大きなバイナリデータの操作は非常に遅くなります。

Fast SQLはこの問題を解決します。デバイス上にローカルHTTPサーバーを確立し、ネイティブSQLiteデータベースと直接通信します。このカスタムプロトコルはCapacitorのブリッジをバイパスし、シリアル化のオーバーヘッドを排除し、以下を実現します:

  • バッチ操作と大規模データセットで最大25倍高速化
  • base64エンコードなしの効率的なバイナリデータ転送
  • メモリの問題のない大規模な結果のストリーミング
  • CRDTとオペレーショナルトランスフォームのような同期システムの最適なパフォーマンス

これにより、Fast SQLはローカルファースト アプリケーション、オフライン同期システム、およびIndexedDBをより信頼性が高く高性能なソリューションに置き換える必要があるシナリオに最適です。

Terminal window
npm install @capgo/capacitor-fast-sql
npx cap sync

Add the following to your Info.plist to allow local networking:

ios/App/App/Info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>

If needed, add to your AndroidManifest.xml:

android/app/src/main/AndroidManifest.xml
<application
android:usesCleartextTraffic="true">
...
</application>

For web platform support, install sql.js:

Terminal window
npm install sql.js
import { FastSQL } from '@capgo/capacitor-fast-sql';
// Connect to database (creates file if it doesn't exist)
const db = await FastSQL.connect({
database: 'myapp'
});
console.log('Connected to database on port:', db.port);
// Create a table
await db.execute(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE,
created_at INTEGER DEFAULT (strftime('%s', 'now'))
)
`);
// Insert single row
const result = await db.run(
'INSERT INTO users (name, email) VALUES (?, ?)',
['John Doe', 'john@example.com']
);
console.log('Inserted row ID:', result.insertId);
console.log('Rows affected:', result.rowsAffected);
// Query with parameters
const users = await db.query(
'SELECT * FROM users WHERE name LIKE ?',
['John%']
);
console.log('Found users:', users);
// users is an array of objects:
// [{ id: 1, name: 'John Doe', email: 'john@example.com', created_at: 1234567890 }]
const result = await db.run(
'UPDATE users SET email = ? WHERE id = ?',
['newemail@example.com', 1]
);
console.log('Updated rows:', result.rowsAffected);
const result = await db.run(
'DELETE FROM users WHERE id = ?',
[1]
);
console.log('Deleted rows:', result.rowsAffected);

Transactions ensure atomicity - either all operations succeed or all are rolled back:

try {
await db.transaction(async (tx) => {
// All operations in this block are part of the transaction
await tx.run('INSERT INTO accounts (name, balance) VALUES (?, ?)', ['Alice', 1000]);
await tx.run('INSERT INTO accounts (name, balance) VALUES (?, ?)', ['Bob', 500]);
// Transfer money
await tx.run('UPDATE accounts SET balance = balance - 100 WHERE name = ?', ['Alice']);
await tx.run('UPDATE accounts SET balance = balance + 100 WHERE name = ?', ['Bob']);
});
console.log('Transaction committed successfully!');
} catch (error) {
console.error('Transaction rolled back:', error);
// All changes are automatically rolled back on error
}
import { FastSQL, IsolationLevel } from '@capgo/capacitor-fast-sql';
await db.transaction(async (tx) => {
// Your operations
}, IsolationLevel.Serializable);

Available isolation levels:

  • ReadUncommitted - Lowest isolation, highest performance
  • ReadCommitted - Prevent dirty reads
  • RepeatableRead - Prevent non-repeatable reads
  • Serializable - Highest isolation, prevents all anomalies

Execute multiple statements efficiently:

const results = await db.executeBatch([
{
statement: 'INSERT INTO logs (message, level) VALUES (?, ?)',
params: ['App started', 'INFO']
},
{
statement: 'INSERT INTO logs (message, level) VALUES (?, ?)',
params: ['User logged in', 'INFO']
},
{
statement: 'INSERT INTO logs (message, level) VALUES (?, ?)',
params: ['Error occurred', 'ERROR']
},
]);
console.log('Executed', results.length, 'statements');

Store and retrieve binary data using Uint8Array:

// Store binary data
const imageData = new Uint8Array([0xFF, 0xD8, 0xFF, 0xE0, /* ... */]);
await db.run(
'INSERT INTO images (name, data) VALUES (?, ?)',
['photo.jpg', imageData]
);
// Retrieve binary data
const rows = await db.query('SELECT data FROM images WHERE name = ?', ['photo.jpg']);
const retrievedData = rows[0].data; // Uint8Array

Enable SQLCipher encryption for secure storage:

const db = await FastSQL.connect({
database: 'secure_db',
encrypted: true,
encryptionKey: 'your-secure-encryption-key'
});

Open databases in read-only mode to prevent modifications:

const db = await FastSQL.connect({
database: 'myapp',
readOnly: true
});

Always close database connections when done:

await FastSQL.disconnect('myapp');

For maximum performance with large datasets, use the HTTP protocol directly:

const { port, token } = await FastSQL.getServerInfo({ database: 'myapp' });
// Make direct HTTP requests to localhost:port
// Include token in Authorization header
const response = await fetch(`http://localhost:${port}/execute`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
statement: 'SELECT * FROM users',
params: []
})
});
const result = await response.json();
import { FastSQL } from '@capgo/capacitor-fast-sql';
try {
const db = await FastSQL.connect({ database: 'myapp' });
await db.run('INSERT INTO users (name, email) VALUES (?, ?)', ['John', 'john@example.com']);
} catch (error) {
if (error.message.includes('UNIQUE constraint failed')) {
console.error('Email already exists');
} else if (error.message.includes('no such table')) {
console.error('Table does not exist');
} else {
console.error('Database error:', error);
}
}
const result = await db.query(
"SELECT name FROM sqlite_master WHERE type='table' AND name=?",
['users']
);
const tableExists = result.length > 0;
const schema = await db.query('PRAGMA table_info(users)');
console.log('Columns:', schema);
const result = await db.query('SELECT COUNT(*) as count FROM users');
const count = result[0].count;
const pageSize = 20;
const page = 1;
const offset = (page - 1) * pageSize;
const users = await db.query(
'SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?',
[pageSize, offset]
);
  1. 複数の操作にはトランザクションを使用 - 個別のコミットより大幅に高速
  2. バルク挿入にはバッチ操作を使用 - ループより効率的
  3. 頻繁にクエリされるカラムにインデックスを作成
  4. パラメータ (?) 付きの準備済みステートメントを使用 - SQLインジェクションを防止しパフォーマンスを向上
  5. 非常に大きな結果セットにはHTTPプロトコルを直接使用
  6. 使用しない場合は接続を閉じて リソースを解放

完全なチュートリアルで以下を含む高度なパターンを確認してください:

  • データベースサービスアーキテクチャ
  • マイグレーションシステム
  • 同期エンジン
  • 複雑なクエリとジョイン
  • パフォーマンス最適化