Transactions
Manual transaction control for grouping multiple statements atomically, and why try/catch
alone does not roll one back.
Basic pattern
const begun = await CapacitorSqlite.beginTransaction({ database: 'myapp' });
if (!begun.success) throw new Error(begun.error.message);
try {
const updated = await CapacitorSqlite.run({ database: 'myapp', statement: 'UPDATE ...', values: [] });
if (!updated.success) throw new Error(updated.error.message);
const batched = await CapacitorSqlite.runBatch({ database: 'myapp', set: [], transaction: false });
if (!batched.success) throw new Error(batched.error.message);
const committed = await CapacitorSqlite.commitTransaction({ database: 'myapp' });
if (!committed.success) throw new Error(committed.error.message);
} catch (e) {
const rolledBack = await CapacitorSqlite.rollbackTransaction({ database: 'myapp' });
if (!rolledBack.success && rolledBack.error.code !== 'TRANSACTION_FAILED') {
console.error('Rollback failed:', rolledBack.error);
}
throw e;
}
Why you must check success, not just catch
Every plugin method resolves to SqliteResult — SQL failures do not reject the Promise. A failed
run(), runBatch(), or commitTransaction() resolves with success: false instead of
throwing. The pattern above only reaches its catch block because each step explicitly
throws when success is false; without that check, a failed statement inside the try block
would be silently ignored and the transaction would still attempt to commit.
Nesting rules
Manual transactions are connection-scoped, one at a time:
- Calling
beginTransaction()again while one is already active returnsTRANSACTION_FAILED. - Calling
execute()orrunBatch()with their defaulttransaction: truewhile a manual transaction is active also returnsTRANSACTION_FAILED— passtransaction: falseon those calls so they participate in the existing transaction instead of nesting a new one, as shown forrunBatch()above.
Cleanup
close() automatically rolls back any transaction still open on that connection — you do not
need to roll back manually before closing.
OR ROLLBACK conflict clauses
A statement using SQLite's OR ROLLBACK conflict-resolution clause can end an active transaction
on its own, outside the plugin's explicit commitTransaction()/rollbackTransaction() calls.
Backends that mirror transaction state resynchronize that mirror after a statement using
OR ROLLBACK fails, so subsequent calls see the correct (no-longer-in-transaction) state.
Next step
Bulk writes covers runBatch() and runMany() for grouping many writes
efficiently, including how their own transaction option interacts with a manual transaction.