0
# Transaction Management
1
2
Enhanced transaction interface with automatic completion handling and convenient store access.
3
4
## Capabilities
5
6
### Transaction Properties
7
8
Access transaction metadata and associated objects.
9
10
```typescript { .api }
11
/**
12
* The transaction's mode
13
*/
14
readonly mode: Mode;
15
16
/**
17
* The names of stores in scope for this transaction
18
*/
19
readonly objectStoreNames: TypedDOMStringList<TxStores[number]>;
20
21
/**
22
* The transaction's connection
23
*/
24
readonly db: IDBPDatabase<DBTypes>;
25
26
/**
27
* Promise for the completion of this transaction
28
* Resolves when transaction completes successfully
29
* Rejects if transaction is aborted or encounters an error
30
*/
31
readonly done: Promise<void>;
32
33
/**
34
* The associated object store, if the transaction covers a single store
35
* Undefined if transaction covers multiple stores
36
*/
37
readonly store: TxStores[1] extends undefined
38
? IDBPObjectStore<DBTypes, TxStores, TxStores[0], Mode>
39
: undefined;
40
```
41
42
**Usage Examples:**
43
44
```typescript
45
import { openDB } from "idb";
46
47
const db = await openDB("my-database");
48
49
// Single store transaction
50
const tx = db.transaction("users", "readwrite");
51
console.log("Transaction mode:", tx.mode); // "readwrite"
52
console.log("Store names:", [...tx.objectStoreNames]); // ["users"]
53
54
// Access single store directly
55
const userStore = tx.store; // Available because only one store
56
await userStore.add({ name: "Alice" });
57
await tx.done; // Wait for transaction completion
58
59
// Multiple store transaction
60
const tx2 = db.transaction(["users", "posts"], "readwrite");
61
console.log("Store names:", [...tx2.objectStoreNames]); // ["users", "posts"]
62
console.log("Direct store access:", tx2.store); // undefined (multiple stores)
63
64
// Must access stores explicitly
65
const userStore2 = tx2.objectStore("users");
66
const postStore = tx2.objectStore("posts");
67
```
68
69
### Object Store Access
70
71
Get object stores within the transaction scope.
72
73
```typescript { .api }
74
/**
75
* Returns an IDBObjectStore in the transaction's scope
76
* @param name - Name of the object store
77
* @returns Enhanced object store interface
78
*/
79
objectStore<StoreName extends TxStores[number]>(
80
name: StoreName
81
): IDBPObjectStore<DBTypes, TxStores, StoreName, Mode>;
82
```
83
84
**Usage Examples:**
85
86
```typescript
87
// Single store transaction with explicit access
88
const tx = db.transaction("users", "readwrite");
89
const userStore = tx.objectStore("users");
90
await userStore.add({ name: "Bob" });
91
92
// Multiple store transaction
93
const tx2 = db.transaction(["users", "posts"], "readwrite");
94
const userStore2 = tx2.objectStore("users");
95
const postStore = tx2.objectStore("posts");
96
97
// Add user and their first post in same transaction
98
const userId = await userStore2.add({ name: "Charlie", email: "charlie@example.com" });
99
await postStore.add({ title: "My First Post", authorId: userId });
100
101
await tx2.done; // Both operations complete together
102
```
103
104
### Transaction Completion
105
106
Handle transaction completion and error scenarios.
107
108
```typescript { .api }
109
/**
110
* Promise that resolves when the transaction completes successfully
111
* Rejects if the transaction is aborted or encounters an error
112
*/
113
readonly done: Promise<void>;
114
```
115
116
**Transaction Completion Examples:**
117
118
```typescript
119
// Basic transaction completion
120
const tx = db.transaction("users", "readwrite");
121
try {
122
await tx.store.add({ name: "Alice" });
123
await tx.store.add({ name: "Bob" });
124
await tx.done; // Wait for both operations to complete
125
console.log("Transaction completed successfully");
126
} catch (error) {
127
console.log("Transaction failed:", error);
128
}
129
130
// Multiple operations with error handling
131
const tx2 = db.transaction(["users", "posts"], "readwrite");
132
const userStore = tx2.objectStore("users");
133
const postStore = tx2.objectStore("posts");
134
135
try {
136
// These operations are atomic - all succeed or all fail
137
const userId = await userStore.add({ name: "Dave" });
138
await postStore.add({ title: "Post 1", authorId: userId });
139
await postStore.add({ title: "Post 2", authorId: userId });
140
141
await tx2.done; // Ensure everything is committed
142
console.log("User and posts created successfully");
143
} catch (error) {
144
console.log("Failed to create user and posts:", error);
145
// All operations are rolled back automatically
146
}
147
148
// Transaction with conditional operations
149
const tx3 = db.transaction(["users", "settings"], "readwrite");
150
try {
151
const existingUser = await tx3.objectStore("users").get("user123");
152
153
if (!existingUser) {
154
await tx3.objectStore("users").add({ id: "user123", name: "New User" });
155
await tx3.objectStore("settings").add({ userId: "user123", theme: "dark" });
156
} else {
157
await tx3.objectStore("users").put({ ...existingUser, lastLogin: new Date() });
158
}
159
160
await tx3.done;
161
} catch (error) {
162
console.log("Transaction failed:", error);
163
}
164
```
165
166
### Transaction Options
167
168
Configure transaction behavior with durability and other options.
169
170
```typescript { .api }
171
interface IDBTransactionOptions {
172
/**
173
* The durability of the transaction
174
* - "default": Browser's default durability behavior
175
* - "strict": Ensures data is written to disk before completion
176
* - "relaxed": Better performance with fewer guarantees
177
*/
178
durability?: 'default' | 'strict' | 'relaxed';
179
}
180
```
181
182
**Transaction Options Examples:**
183
184
```typescript
185
// High durability for critical data
186
const criticalTx = db.transaction("financial_records", "readwrite", {
187
durability: "strict"
188
});
189
await criticalTx.store.add({ amount: 1000, type: "deposit" });
190
await criticalTx.done; // Guaranteed to be written to disk
191
192
// Better performance for temporary data
193
const cacheTx = db.transaction("cache", "readwrite", {
194
durability: "relaxed"
195
});
196
await cacheTx.store.put({ key: "temp_data", value: someData });
197
await cacheTx.done; // May complete before writing to disk
198
199
// Default durability (most common)
200
const normalTx = db.transaction("users", "readwrite", {
201
durability: "default"
202
});
203
await normalTx.store.add({ name: "User" });
204
await normalTx.done;
205
```
206
207
### Advanced Transaction Patterns
208
209
Complex transaction workflows and patterns.
210
211
**Batch Operations:**
212
213
```typescript
214
async function batchInsertUsers(users: User[]) {
215
const tx = db.transaction("users", "readwrite");
216
const userStore = tx.store;
217
218
// Start all operations without awaiting
219
const promises = users.map(user => userStore.add(user));
220
221
// Wait for all operations to complete
222
await Promise.all([...promises, tx.done]);
223
224
console.log(`Successfully added ${users.length} users`);
225
}
226
```
227
228
**Transaction Rollback on Custom Conditions:**
229
230
```typescript
231
async function transferBetweenAccounts(fromId: string, toId: string, amount: number) {
232
const tx = db.transaction("accounts", "readwrite");
233
const accountStore = tx.store;
234
235
try {
236
const fromAccount = await accountStore.get(fromId);
237
const toAccount = await accountStore.get(toId);
238
239
if (!fromAccount || !toAccount) {
240
throw new Error("Account not found");
241
}
242
243
if (fromAccount.balance < amount) {
244
throw new Error("Insufficient funds");
245
}
246
247
// Update balances
248
await accountStore.put({
249
...fromAccount,
250
balance: fromAccount.balance - amount
251
});
252
253
await accountStore.put({
254
...toAccount,
255
balance: toAccount.balance + amount
256
});
257
258
await tx.done; // Commit the transaction
259
console.log("Transfer completed successfully");
260
261
} catch (error) {
262
// Transaction automatically rolls back on error
263
console.log("Transfer failed:", error.message);
264
throw error;
265
}
266
}
267
```
268
269
**Long-running Transactions with Progress Tracking:**
270
271
```typescript
272
async function processLargeDataset(data: any[]) {
273
const batchSize = 100;
274
const totalBatches = Math.ceil(data.length / batchSize);
275
276
for (let i = 0; i < totalBatches; i++) {
277
const batch = data.slice(i * batchSize, (i + 1) * batchSize);
278
const tx = db.transaction("processed_data", "readwrite");
279
280
try {
281
for (const item of batch) {
282
await tx.store.add(processItem(item));
283
}
284
285
await tx.done;
286
console.log(`Processed batch ${i + 1}/${totalBatches}`);
287
288
} catch (error) {
289
console.log(`Failed to process batch ${i + 1}:`, error);
290
throw error;
291
}
292
}
293
}
294
```
295
296
### Transaction Lifecycle
297
298
Understanding transaction states and lifecycle management.
299
300
```typescript
301
// Transaction begins when created
302
const tx = db.transaction("users", "readwrite");
303
304
// Transaction is active during operations
305
const userStore = tx.store;
306
await userStore.add({ name: "Alice" });
307
308
// Transaction can be explicitly aborted
309
// tx.abort(); // Would cause tx.done to reject
310
311
// Transaction completes when all operations finish
312
// and no more operations are queued
313
await tx.done; // Transaction is now complete
314
315
// Attempting operations after completion throws error
316
// await userStore.add({ name: "Bob" }); // Would throw TransactionInactiveError
317
```