IndexedDB Atomic Transactions in JavaScript
IndexedDB ensures reliable client-side data storage in the browser by implementing strict transactional models based on ACID (Atomicity, Consistency, Isolation, Durability) principles. This article explores how IndexedDB achieves atomic read and write safety in JavaScript using structured transaction modes, object store scoping, internal locking mechanisms, and automated commit and rollback lifecycles.
The Principle of Atomicity in IndexedDB
Atomicity guarantees that a series of database operations executes as a single, indivisible unit. In IndexedDB, all read and write operations must occur within the context of an explicit transaction. If every operation within the transaction succeeds, all modifications are permanently applied to the database. If a single operation fails or is intentionally aborted, all pending changes within that transaction are rolled back, leaving the database in its original state before the transaction began.
Transaction Scopes and Modes
When opening a transaction, developers must explicitly declare the target object stores (scope) and access mode. This boundary declaration allows the browser’s storage engine to manage concurrency safely:
readonlyMode: Multiplereadonlytransactions can access the same object stores simultaneously. They permit data retrieval without modifying records, ensuring zero risk of write conflicts.readwriteMode: Allows reading and modifying records. Only onereadwritetransaction can modify an overlapping object store at any given time.versionchangeMode: Used exclusively during database creation or upgrades (viaonupgradeneeded) to alter database schemas, create object stores, or manage indexes.
// Opening a readwrite transaction scoped to a specific store
const transaction = db.transaction(["users"], "readwrite");
const userStore = transaction.objectStore("users");
userStore.put({ id: 1, name: "Alice", balance: 100 });
userStore.put({ id: 2, name: "Bob", balance: 50 });Internal Locking and Concurrency Control
IndexedDB enforces data isolation and race-condition prevention through non-blocking internal locks:
- Shared Locks: Granted to
readonlytransactions. Multiple shared locks can coexist on the same object store. - Exclusive Locks: Required by
readwritetransactions. An exclusive lock will not be granted until all active transactions on that scope are complete. While an exclusive lock is active, subsequent read or write requests to that store are queued.
Because JavaScript runs on a single-threaded event loop, IndexedDB offloads database operations to background I/O threads while maintaining an asynchronous request queue. This architecture prevents UI thread blocking while guaranteeing deterministic execution order.
Lifecycle, Auto-Commit, and Rollback Mechanisms
IndexedDB transactions utilize an automated lifecycle tied directly to the JavaScript event loop:
- Auto-Commit: A transaction begins automatically
when created and remains active as long as requests (
get,put,delete) are queued. Once all queued requests complete and no new requests are added during the current microtask/event tick, the browser automatically commits the transaction. - Automatic Rollback: If an unhandled error occurs on
any single request, the
errorevent bubbles up to the transaction, automatically invoking an internal abort. - Explicit Abort: Developers can manually cancel a
transaction by calling
transaction.abort().
const transaction = db.transaction(["accounts"], "readwrite");
const store = transaction.objectStore("accounts");
// Operation 1: Deduct balance
const deductRequest = store.put({ id: "acc_1", balance: 40 });
// Operation 2: Add balance
const addRequest = store.put({ id: "acc_2", balance: 160 });
// Handle transaction failure
transaction.onerror = (event) => {
// If either operation fails, both are rolled back automatically
console.error("Transaction failed and rolled back:", event.target.error);
};
transaction.oncomplete = () => {
console.log("All operations committed successfully.");
};By coupling strict locking queues with automated rollback capabilities, IndexedDB ensures that partial updates, dirty reads, and write collisions cannot corrupt client-side application data.