0
# Transaction Management
1
2
Transaction handling including explicit transactions and managed transactions with automatic retry logic for robust database operations.
3
4
## Capabilities
5
6
### Explicit Transaction Control
7
8
Manual transaction management with full control over commit and rollback operations.
9
10
```typescript { .api }
11
interface Transaction {
12
/**
13
* Run a Cypher query within the transaction
14
* @param query - The Cypher query string
15
* @param parameters - Query parameters as key-value pairs
16
* @returns Promise resolving to query result
17
*/
18
run(query: string, parameters?: Parameters): Promise<Result>;
19
20
/** Commit the transaction and make changes permanent */
21
commit(): Promise<void>;
22
23
/** Rollback the transaction and discard changes */
24
rollback(): Promise<void>;
25
26
/** Check if the transaction is still open and active */
27
isOpen(): boolean;
28
}
29
```
30
31
**Usage Examples:**
32
33
```typescript
34
const session = neo4jDriver.session();
35
36
// Basic transaction usage
37
const tx = await session.beginTransaction();
38
try {
39
const result = await tx.run(
40
"CREATE (p:Person {name: $name}) RETURN p",
41
{ name: "Alice" }
42
);
43
44
await tx.commit();
45
console.log("Transaction committed");
46
} catch (error) {
47
await tx.rollback();
48
console.error("Transaction rolled back:", error);
49
} finally {
50
await session.close();
51
}
52
53
// Complex multi-step transaction
54
const complexTx = await session.beginTransaction({
55
timeout: 60000, // 1 minute timeout
56
metadata: { operation: "user_registration" }
57
});
58
59
try {
60
// Step 1: Create user
61
const userResult = await complexTx.run(`
62
CREATE (u:User {id: randomUUID(), email: $email, createdAt: datetime()})
63
RETURN u.id AS userId
64
`, { email: "user@example.com" });
65
66
const userId = userResult.records[0].get("userId");
67
68
// Step 2: Create user profile
69
await complexTx.run(`
70
MATCH (u:User {id: $userId})
71
CREATE (u)-[:HAS_PROFILE]->(p:Profile {
72
firstName: $firstName,
73
lastName: $lastName,
74
updatedAt: datetime()
75
})
76
`, {
77
userId,
78
firstName: "John",
79
lastName: "Doe"
80
});
81
82
// Step 3: Add to default groups
83
await complexTx.run(`
84
MATCH (u:User {id: $userId}), (g:Group {name: 'users'})
85
CREATE (u)-[:MEMBER_OF]->(g)
86
`, { userId });
87
88
await complexTx.commit();
89
console.log(`User ${userId} registered successfully`);
90
} catch (error) {
91
await complexTx.rollback();
92
console.error("User registration failed:", error);
93
} finally {
94
await session.close();
95
}
96
```
97
98
### Managed Transactions
99
100
Managed transactions with automatic retry logic and simplified error handling.
101
102
```typescript { .api }
103
interface ManagedTransaction {
104
/**
105
* Run a Cypher query within the managed transaction
106
* @param query - The Cypher query string
107
* @param parameters - Query parameters as key-value pairs
108
* @returns Promise resolving to query result
109
*/
110
run(query: string, parameters?: Parameters): Promise<Result>;
111
}
112
113
interface Session {
114
/**
115
* Execute a read transaction with automatic retry logic
116
* @param work - Function containing read operations
117
* @param config - Optional transaction configuration
118
* @returns Promise resolving to the work function result
119
*/
120
executeRead<T>(
121
work: (tx: ManagedTransaction) => Promise<T>,
122
config?: TransactionConfig
123
): Promise<T>;
124
125
/**
126
* Execute a write transaction with automatic retry logic
127
* @param work - Function containing write operations
128
* @param config - Optional transaction configuration
129
* @returns Promise resolving to the work function result
130
*/
131
executeWrite<T>(
132
work: (tx: ManagedTransaction) => Promise<T>,
133
config?: TransactionConfig
134
): Promise<T>;
135
}
136
```
137
138
**Usage Examples:**
139
140
```typescript
141
const session = neo4jDriver.session();
142
143
try {
144
// Read transaction - automatically retried on failure
145
const users = await session.executeRead(async tx => {
146
const result = await tx.run(`
147
MATCH (u:User)-[:HAS_PROFILE]->(p:Profile)
148
WHERE u.createdAt > datetime({year: 2023})
149
RETURN u.email, p.firstName, p.lastName
150
ORDER BY u.createdAt DESC
151
LIMIT 100
152
`);
153
154
return result.records.map(record => ({
155
email: record.get("u.email"),
156
firstName: record.get("p.firstName"),
157
lastName: record.get("p.lastName")
158
}));
159
});
160
161
console.log(`Found ${users.length} recent users`);
162
163
// Write transaction with retry logic
164
const orderId = await session.executeWrite(async tx => {
165
// Create order
166
const orderResult = await tx.run(`
167
CREATE (o:Order {
168
id: randomUUID(),
169
status: 'pending',
170
createdAt: datetime(),
171
total: $total
172
})
173
RETURN o.id AS orderId
174
`, { total: 99.99 });
175
176
const id = orderResult.records[0].get("orderId");
177
178
// Add order items
179
await tx.run(`
180
MATCH (o:Order {id: $orderId})
181
UNWIND $items AS item
182
CREATE (o)-[:CONTAINS]->(oi:OrderItem {
183
productId: item.productId,
184
quantity: item.quantity,
185
price: item.price
186
})
187
`, {
188
orderId: id,
189
items: [
190
{ productId: "prod-123", quantity: 2, price: 49.99 },
191
{ productId: "prod-456", quantity: 1, price: 0.01 } // Tax adjustment
192
]
193
});
194
195
return id;
196
}, {
197
timeout: 30000,
198
metadata: { operation: "create_order", version: "v2" }
199
});
200
201
console.log(`Created order: ${orderId}`);
202
} finally {
203
await session.close();
204
}
205
```
206
207
### Transaction Configuration
208
209
Configuration options for controlling transaction behavior.
210
211
```typescript { .api }
212
interface TransactionConfig {
213
/** Transaction timeout in milliseconds */
214
timeout?: number;
215
216
/**
217
* Transaction metadata for monitoring and debugging
218
* Useful for tracking operations in Neo4j logs
219
*/
220
metadata?: Record<string, any>;
221
}
222
```
223
224
**Usage Examples:**
225
226
```typescript
227
// Long-running transaction with custom timeout
228
await session.executeWrite(async tx => {
229
// Bulk data import operation
230
const result = await tx.run(`
231
LOAD CSV WITH HEADERS FROM $csvUrl AS row
232
CREATE (p:Product {
233
id: row.id,
234
name: row.name,
235
price: toFloat(row.price),
236
category: row.category,
237
importedAt: datetime()
238
})
239
`, { csvUrl: "file:///import/products.csv" });
240
241
return result.summary.counters.nodesCreated;
242
}, {
243
timeout: 300000, // 5 minutes for large import
244
metadata: {
245
operation: "bulk_import",
246
source: "products.csv",
247
batchId: "batch-001"
248
}
249
});
250
251
// Transaction with detailed metadata
252
await session.executeWrite(async tx => {
253
await tx.run(`
254
MATCH (u:User {id: $userId})
255
SET u.lastLogin = datetime(),
256
u.loginCount = coalesce(u.loginCount, 0) + 1
257
`, { userId: "user-123" });
258
}, {
259
metadata: {
260
operation: "user_login",
261
userId: "user-123",
262
timestamp: new Date().toISOString(),
263
source: "web_app"
264
}
265
});
266
```
267
268
### Transaction Best Practices
269
270
**Retry Logic:**
271
Managed transactions automatically retry on transient errors like connection issues or deadlocks. The driver uses exponential backoff and respects cluster topology changes.
272
273
**Read vs Write Transactions:**
274
- Use `executeRead` for queries that only read data
275
- Use `executeWrite` for queries that modify data
276
- This enables proper routing in cluster environments
277
278
**Transaction Size:**
279
- Keep transactions small and focused
280
- Avoid long-running transactions that hold locks
281
- Consider breaking large operations into smaller transactions
282
283
**Error Handling:**
284
- Managed transactions handle retryable errors automatically
285
- Non-retryable errors (like constraint violations) are thrown immediately
286
- Always handle business logic errors in your work function
287
288
**Performance Tips:**
289
- Use parameters instead of string concatenation
290
- Batch related operations in single transactions
291
- Use UNWIND for bulk operations
292
- Profile queries to optimize performance
293
294
```typescript
295
// Good: Focused transaction
296
await session.executeWrite(async tx => {
297
await tx.run(`
298
MATCH (u:User {id: $userId})
299
SET u.status = $status, u.updatedAt = datetime()
300
`, { userId, status: "active" });
301
});
302
303
// Good: Bulk operation with UNWIND
304
await session.executeWrite(async tx => {
305
await tx.run(`
306
UNWIND $users AS user
307
MERGE (u:User {id: user.id})
308
SET u.email = user.email, u.updatedAt = datetime()
309
`, { users: userBatch });
310
});
311
312
// Avoid: Transaction too large
313
await session.executeWrite(async tx => {
314
// Too many operations in single transaction
315
for (const user of allUsers) { // Could be thousands
316
await tx.run("CREATE (u:User $props)", { props: user });
317
}
318
});
319
```